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

from oslo_policy import policy

from nova.policies import base

POLICY_ROOT = 'os_compute_api:os-shelve:%s'

shelve_policies = [
    policy.DocumentedRuleDefault(
        POLICY_ROOT % 'shelve',
        base.RULE_ADMIN_OR_OWNER,
        "Shelve server",
        [
            {
                'method': 'POST',
                'path': '/servers/{server_id}/action (shelve)'
            }
        ]),
    policy.DocumentedRuleDefault(
        POLICY_ROOT % 'unshelve',
        base.RULE_ADMIN_OR_OWNER,
        "Unshelve (restore) shelved server",
        [
            {
                'method': 'POST',
                'path': '/servers/{server_id}/action (unshelve)'
            }
        ]),
    policy.DocumentedRuleDefault(
        POLICY_ROOT % 'shelve_offload',
        base.RULE_ADMIN_API,
        "Shelf-offload (remove) server",
        [
            {
                'method': 'POST',
                'path': '/servers/{server_id}/action (shelveOffload)'
            }
        ]),
]

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

from oslo_policy import policy

from nova.policies import base

POLICY_ROOT = 'os_compute_api:os-shelve:%s'

shelve_policies = [
    policy.DocumentedRuleDefault(
        name=POLICY_ROOT % 'shelve',
        check_str=base.RULE_ADMIN_OR_OWNER,
        description="Shelve server",
        operations=[
            {
                'method': 'POST',
                'path': '/servers/{server_id}/action (shelve)'
            }
        ],
        scope_types=['system', 'project']),
    policy.DocumentedRuleDefault(
        name=POLICY_ROOT % 'unshelve',
        check_str=base.RULE_ADMIN_OR_OWNER,
        description="Unshelve (restore) shelved server",
        operations=[
            {
                'method': 'POST',
                'path': '/servers/{server_id}/action (unshelve)'
            }
        ],
        scope_types=['system', 'project']),
    policy.DocumentedRuleDefault(
        name=POLICY_ROOT % 'shelve_offload',
        check_str=base.RULE_ADMIN_API,
        description="Shelf-offload (remove) server",
        operations=[
            {
                'method': 'POST',
                'path': '/servers/{server_id}/action (shelveOffload)'
            }
        ],
        scope_types=['system', 'project']),
]

def list_rules():
    return shelve_policies
<|endoftext|>


<commit_before>"""Interface to the liblzma compression library.

This module provides a class for reading and writing compressed files,
classes for incremental (de)compression, and convenience functions for
one-shot (de)compression.

These classes and functions support both the XZ and legacy LZMA
container formats, as well as raw compressed data streams.
"""

__all__ = [
    "CHECK_NONE", "CHECK_CRC32", "CHECK_CRC64", "CHECK_SHA256",
    "CHECK_ID_MAX", "CHECK_UNKNOWN",
    "FILTER_LZMA1", "FILTER_LZMA2", "FILTER_DELTA", "FILTER_X86", "FILTER_IA64",
    "FILTER_ARM", "FILTER_ARMTHUMB", "FILTER_POWERPC", "FILTER_SPARC",
    "FORMAT_AUTO", "FORMAT_XZ", "FORMAT_ALONE", "FORMAT_RAW",
    "MF_HC3", "MF_HC4", "MF_BT2", "MF_BT3", "MF_BT4",
    "MODE_FAST", "MODE_NORMAL", "PRESET_DEFAULT", "PRESET_EXTREME",

    "LZMACompressor", "LZMADecompressor", "LZMAFile", "LZMAError",
    "open", "compress", "decompress", "is_check_supported",
]

try:
    #Python 3
    import builtins
except ImportError:
    #Python 2
    builtins = __builtins__
import io
from ._lzma import *
from ._lzma import _encode_filter_properties, _decode_filter_properties

_MODE_CLOSED   = 0
_MODE_READ     = 1
_MODE_READ_EOF = 2
_MODE_WRITE    = 3

_BUFFER_SIZE = 8192

class LZMAFile(io.BufferedIOBase):

    """A file object providing transparent LZMA (de)compression.

    An LZMAFile can act as a wrapper for an existing file object, or
    refer directly to a named file on disk.

    Note that LZMAFile provides a *binary* file interface - data read
    is returned as bytes, and data to be written must be given as bytes.
    """

    def __init__(self, filename=None, mode="r",
                 format=None, check=-1, preset=None, filters=None):
        """Open an LZMA-compressed file in binary mode.

        filename can be either an actual file name (given as a str or
        bytes object), in which case the named file is opened, or it can
        be an existing file object to read from or write to.

        mode can be "r" for reading (default), "w" for (over)writing, or
        "a" for appending. These can equivalently be given as "rb", "wb",
        and "ab" respectively.

        format specifies the container format to use for the file.
        If mode is "r", this defaults to FORMAT_AUTO. Otherwise, the
        default is FORMAT_XZ.

        check specifies the integrity check to use. This argument can
        only be used when opening a file for writing. For FORMAT_XZ,
        the default is CHECK_CRC64. FORMAT_ALONE and FORMAT_RAW do not
        support integrity checks - for these formats, check must be
        omitted, or be CHECK_NONE.

        When opening a file for reading, the *preset* argument is not
        meaningful, and should be omitted. The *filters* argument should
        also be omitted, except when format is FORMAT_RAW (in which case
        it is required).

        When opening a file for writing, the settings used by the
        compressor can be specified either as a preset compression
        level (with the *preset* argument), or in detail as a custom
        filter chain (with the *filters* argument). For FORMAT_XZ and
        FORMAT_ALONE, the default is to use the PRESET_DEFAULT preset
        level. For FORMAT_RAW, the caller must always specify a filter
        chain; the raw compressor does not support preset compression
        levels.

        preset (if provided) should be an integer in the range 0-9,
        optionally OR-ed with the constant PRESET_EXTREME.

        filters (if provided) should be a sequence of dicts. Each dict
        should have an entry for "id" indicating ID of the filter, plus
        additional entries for options to the filter.
        """
        self._fp = None
        self._closefp = False
        self._mode = _MODE_CLOSED
        self._pos = 0
        self._size = -1

        if mode in ("r", "rb"):
            if check != -1:
                raise ValueError("Cannot specify an integrity check "
                                 "when opening a file for reading")
            if preset is not None:
                raise ValueError("Cannot specify a preset compression "
                                 "level when opening a file for reading")
            if format is None:
                format = FORMAT_AUTO
            mode_code = _MODE_READ
            # Save the args to pass to the LZMADecompressor initializer.
            # If the file contains multiple compressed streams, each
            # stream will need a separate decompressor object.
            self._init_args = {"format":format, "filters":filters}
            self._decompressor = LZMADecompressor(**self._init_args)
            self._buffer = None
        elif mode in ("w", "wb", "a", "ab"):
            if format is None:
                format = FORMAT_XZ
            mode_code = _MODE_WRITE
            self._compressor = LZMACompressor(format=format, check=check,
                                              preset=preset, filters=filters)
        else:
            raise ValueError("Invalid mode: {!r}".format(mode))

        if isinstance(filename, (str, bytes)):
            if "b" not in mode:
                mode += "b"
            self._fp = builtins.open(filename, mode)
            self._closefp = True
            self._mode = mode_code
        elif hasattr(filename, "read") or hasattr(filename, "write"):
            self._fp = filename
            self._mode = mode_code
        else:
            raise TypeError("filename must be a str or bytes object, or a file")

    def close(self):
        """Flush and close the file.

        May be called more than once without error. Once the file is
        closed, any other operation on it will raise a ValueError.
        """
        if self._mode == _MODE_CLOSED:
            return
        try:
            if self._mode in (_MODE_READ, _MODE_READ_EOF):
                self._decompressor = None
                self._buffer = None
            elif self._mode == _MODE_WRITE:
                self._fp.write(self._compressor.flush())
                self._compressor = None
        finally:
            try:
                if self._closefp:
                    self._fp.close()
            finally:
                self._fp = None
                self._closefp = False
                self._mode = _MODE_CLOSED

    @property
    def closed(self):
        """True if this file is closed."""
        return self._mode == _MODE_CLOSED

    def fileno(self):
        """Return the file descriptor for the underlying file."""
        self._check_not_closed()
        return self._fp.fileno()

    def seekable(self):
        """Return whether the file supports seeking."""
        return self.readable() and self._fp.seekable()

    def readable(self):
        """Return whether the file was opened for reading."""
        self._check_not_closed()
        return self._mode in (_MODE_READ, _MODE_READ_EOF)

    def writable(self):
        """Return whether the file was opened for writing."""
        self._check_not_closed()
        return self._mode == _MODE_WRITE

    # Mode-checking helper functions.

    def _check_not_closed(self):
        if self.closed:
            raise ValueError("I/O operation on closed file")

    def _check_can_read(self):
        if not self.readable():
            raise io.UnsupportedOperation("File not open for reading")

    def _check_can_write(self):
        if not self.writable():
            raise io.UnsupportedOperation("File not open for writing")

    def _check_can_seek(self):
        if not self.readable():
            raise io.UnsupportedOperation("Seeking is only supported "
                                          "on files open for reading")
        if not self._fp.seekable():
            raise io.UnsupportedOperation("The underlying file object "
                                          "does not support seeking")

    # Fill the readahead buffer if it is empty. Returns False on EOF.
    def _fill_buffer(self):
        # Depending on the input data, our call to the decompressor may not
        # return any data. In this case, try again after reading another block.
        while True:
            if self._buffer:
                return True

            if self._decompressor.unused_data:
                rawblock = self._decompressor.unused_data
            else:
                rawblock = self._fp.read(_BUFFER_SIZE)

            if not rawblock:
                if self._decompressor.eof:
                    self._mode = _MODE_READ_EOF
                    self._size = self._pos
                    return False
                else:
                    raise EOFError("Compressed file ended before the "
                                   "end-of-stream marker was reached")

            # Continue to next stream.
            if self._decompressor.eof:
                self._decompressor = LZMADecompressor(**self._init_args)

            self._buffer = self._decompressor.decompress(rawblock)

    # Read data until EOF.
    # If return_data is false, consume the data without returning it.
    def _read_all(self, return_data=True):
        blocks = []
        while self._fill_buffer():
            if return_data:
                blocks.append(self._buffer)
            self._pos += len(self._buffer)
            self._buffer = None
        if return_data:
            return b"".join(blocks)

    # Read a block of up to n bytes.
    # If return_data is false, consume the data without returning it.
    def _read_block(self, n, return_data=True):
        blocks = []
        while n > 0 and self._fill_buffer():
            if n < len(self._buffer):
                data = self._buffer[:n]
                self._buffer = self._buffer[n:]
            else:
                data = self._buffer
                self._buffer = None
            if return_data:
                blocks.append(data)
            self._pos += len(data)
            n -= len(data)
        if return_data:
            return b"".join(blocks)

    def peek(self, size=-1):
        """Return buffered data without advancing the file position.

        Always returns at least one byte of data, unless at EOF.
        The exact number of bytes returned is unspecified.
        """
        self._check_can_read()
        if self._mode == _MODE_READ_EOF or not self._fill_buffer():
            return b""
        return self._buffer

    def read(self, size=-1):
        """Read up to size uncompressed bytes from the file.

        If size is negative or omitted, read until EOF is reached.
        Returns b"" if the file is already at EOF.
        """
        self._check_can_read()
        if self._mode == _MODE_READ_EOF or size == 0:
            return b""
        elif size < 0:
            return self._read_all()
        else:
            return self._read_block(size)

    def read1(self, size=-1):
        """Read up to size uncompressed bytes, while trying to avoid
        making multiple reads from the underlying stream.

        Returns b"" if the file is at EOF.
        """
        # Usually, read1() calls _fp.read() at most once. However, sometimes
        # this does not give enough data for the decompressor to make progress.
        # In this case we make multiple reads, to avoid returning b"".
        self._check_can_read()
        if (size == 0 or self._mode == _MODE_READ_EOF or
            not self._fill_buffer()):
            return b""
        if 0 < size < len(self._buffer):
            data = self._buffer[:size]
            self._buffer = self._buffer[size:]
        else:
            data = self._buffer
            self._buffer = None
        self._pos += len(data)
        return data

    def write(self, data):
        """Write a bytes object to the file.

        Returns the number of uncompressed bytes written, which is
        always len(data). Note that due to buffering, the file on disk
        may not reflect the data written until close() is called.
        """
        self._check_can_write()
        compressed = self._compressor.compress(data)
        self._fp.write(compressed)
        self._pos += len(data)
        return len(data)

    # Rewind the file to the beginning of the data stream.
    def _rewind(self):
        self._fp.seek(0, 0)
        self._mode = _MODE_READ
        self._pos = 0
        self._decompressor = LZMADecompressor(**self._init_args)
        self._buffer = None

    def seek(self, offset, whence=0):
        """Change the file position.

        The new position is specified by offset, relative to the
        position indicated by whence. Possible values for whence are:

            0: start of stream (default): offset must not be negative
            1: current stream position
            2: end of stream; offset must not be positive

        Returns the new file position.

        Note that seeking is emulated, sp depending on the parameters,
        this operation may be extremely slow.
        """
        self._check_can_seek()

        # Recalculate offset as an absolute file position.
        if whence == 0:
            pass
        elif whence == 1:
            offset = self._pos + offset
        elif whence == 2:
            # Seeking relative to EOF - we need to know the file's size.
            if self._size < 0:
                self._read_all(return_data=False)
            offset = self._size + offset
        else:
            raise ValueError("Invalid value for whence: {}".format(whence))

        # Make it so that offset is the number of bytes to skip forward.
        if offset < self._pos:
            self._rewind()
        else:
            offset -= self._pos

        # Read and discard data until we reach the desired position.
        if self._mode != _MODE_READ_EOF:
            self._read_block(offset, return_data=False)

        return self._pos

    def tell(self):
        """Return the current file position."""
        self._check_not_closed()
        return self._pos

def open(filename, mode="rb",
         format=None, check=-1, preset=None, filters=None,
         encoding=None, errors=None, newline=None):
    """Open an LZMA-compressed file in binary or text mode.

    filename can be either an actual file name (given as a str or bytes object),
    in which case the named file is opened, or it can be an existing file object
    to read from or write to.

    The mode argument can be "r", "rb" (default), "w", "wb", "a", or "ab" for
    binary mode, or "rt", "wt" or "at" for text mode.

    The format, check, preset and filters arguments specify the compression
    settings, as for LZMACompressor, LZMADecompressor and LZMAFile.

    For binary mode, this function is equivalent to the LZMAFile constructor:
    LZMAFile(filename, mode, ...). In this case, the encoding, errors and
    newline arguments must not be provided.

    For text mode, a LZMAFile object is created, and wrapped in an
    io.TextIOWrapper instance with the specified encoding, error handling
    behavior, and line ending(s).

    """
    if "t" in mode:
        if "b" in mode:
            raise ValueError("Invalid mode: %r" % (mode,))
    else:
        if encoding is not None:
            raise ValueError("Argument 'encoding' not supported in binary mode")
        if errors is not None:
            raise ValueError("Argument 'errors' not supported in binary mode")
        if newline is not None:
            raise ValueError("Argument 'newline' not supported in binary mode")

    lz_mode = mode.replace("t", "")
    binary_file = LZMAFile(filename, lz_mode, format=format, check=check,
                           preset=preset, filters=filters)

    if "t" in mode:
        return io.TextIOWrapper(binary_file, encoding, errors, newline)
    else:
        return binary_file

def compress(data, format=FORMAT_XZ, check=-1, preset=None, filters=None):
    """Compress a block of data.

    Refer to LZMACompressor's docstring for a description of the
    optional arguments *format*, *check*, *preset* and *filters*.

    For incremental compression, use an LZMACompressor object instead.
    """
    comp = LZMACompressor(format, check, preset, filters)
    return comp.compress(data) + comp.flush()

def decompress(data, format=FORMAT_AUTO, memlimit=None, filters=None):
    """Decompress a block of data.

    Refer to LZMADecompressor's docstring for a description of the
    optional arguments *format*, *check* and *filters*.

    For incremental decompression, use a LZMADecompressor object instead.
    """
    results = []
    while True:
        decomp = LZMADecompressor(format, memlimit, filters)
        results.append(decomp.decompress(data))
        if not decomp.eof:
            raise LZMAError("Compressed data ended before the "
                            "end-of-stream marker was reached")
        if not decomp.unused_data:
            return b"".join(results)
        # There is unused data left over. Proceed to next stream.
        data = decomp.unused_data
<commit_msg>Fix __builtins__ vs __builtin__ confusion (a CPython implementation detail)<commit_after>"""Interface to the liblzma compression library.

This module provides a class for reading and writing compressed files,
classes for incremental (de)compression, and convenience functions for
one-shot (de)compression.

These classes and functions support both the XZ and legacy LZMA
container formats, as well as raw compressed data streams.
"""

__all__ = [
    "CHECK_NONE", "CHECK_CRC32", "CHECK_CRC64", "CHECK_SHA256",
    "CHECK_ID_MAX", "CHECK_UNKNOWN",
    "FILTER_LZMA1", "FILTER_LZMA2", "FILTER_DELTA", "FILTER_X86", "FILTER_IA64",
    "FILTER_ARM", "FILTER_ARMTHUMB", "FILTER_POWERPC", "FILTER_SPARC",
    "FORMAT_AUTO", "FORMAT_XZ", "FORMAT_ALONE", "FORMAT_RAW",
    "MF_HC3", "MF_HC4", "MF_BT2", "MF_BT3", "MF_BT4",
    "MODE_FAST", "MODE_NORMAL", "PRESET_DEFAULT", "PRESET_EXTREME",

    "LZMACompressor", "LZMADecompressor", "LZMAFile", "LZMAError",
    "open", "compress", "decompress", "is_check_supported",
]

try:
    #Python 3
    import builtins
except ImportError:
    #Python 2
    import __builtin__ as builtins
import io
from ._lzma import *
from ._lzma import _encode_filter_properties, _decode_filter_properties

_MODE_CLOSED   = 0
_MODE_READ     = 1
_MODE_READ_EOF = 2
_MODE_WRITE    = 3

_BUFFER_SIZE = 8192

class LZMAFile(io.BufferedIOBase):

    """A file object providing transparent LZMA (de)compression.

    An LZMAFile can act as a wrapper for an existing file object, or
    refer directly to a named file on disk.

    Note that LZMAFile provides a *binary* file interface - data read
    is returned as bytes, and data to be written must be given as bytes.
    """

    def __init__(self, filename=None, mode="r",
                 format=None, check=-1, preset=None, filters=None):
        """Open an LZMA-compressed file in binary mode.

        filename can be either an actual file name (given as a str or
        bytes object), in which case the named file is opened, or it can
        be an existing file object to read from or write to.

        mode can be "r" for reading (default), "w" for (over)writing, or
        "a" for appending. These can equivalently be given as "rb", "wb",
        and "ab" respectively.

        format specifies the container format to use for the file.
        If mode is "r", this defaults to FORMAT_AUTO. Otherwise, the
        default is FORMAT_XZ.

        check specifies the integrity check to use. This argument can
        only be used when opening a file for writing. For FORMAT_XZ,
        the default is CHECK_CRC64. FORMAT_ALONE and FORMAT_RAW do not
        support integrity checks - for these formats, check must be
        omitted, or be CHECK_NONE.

        When opening a file for reading, the *preset* argument is not
        meaningful, and should be omitted. The *filters* argument should
        also be omitted, except when format is FORMAT_RAW (in which case
        it is required).

        When opening a file for writing, the settings used by the
        compressor can be specified either as a preset compression
        level (with the *preset* argument), or in detail as a custom
        filter chain (with the *filters* argument). For FORMAT_XZ and
        FORMAT_ALONE, the default is to use the PRESET_DEFAULT preset
        level. For FORMAT_RAW, the caller must always specify a filter
        chain; the raw compressor does not support preset compression
        levels.

        preset (if provided) should be an integer in the range 0-9,
        optionally OR-ed with the constant PRESET_EXTREME.

        filters (if provided) should be a sequence of dicts. Each dict
        should have an entry for "id" indicating ID of the filter, plus
        additional entries for options to the filter.
        """
        self._fp = None
        self._closefp = False
        self._mode = _MODE_CLOSED
        self._pos = 0
        self._size = -1

        if mode in ("r", "rb"):
            if check != -1:
                raise ValueError("Cannot specify an integrity check "
                                 "when opening a file for reading")
            if preset is not None:
                raise ValueError("Cannot specify a preset compression "
                                 "level when opening a file for reading")
            if format is None:
                format = FORMAT_AUTO
            mode_code = _MODE_READ
            # Save the args to pass to the LZMADecompressor initializer.
            # If the file contains multiple compressed streams, each
            # stream will need a separate decompressor object.
            self._init_args = {"format":format, "filters":filters}
            self._decompressor = LZMADecompressor(**self._init_args)
            self._buffer = None
        elif mode in ("w", "wb", "a", "ab"):
            if format is None:
                format = FORMAT_XZ
            mode_code = _MODE_WRITE
            self._compressor = LZMACompressor(format=format, check=check,
                                              preset=preset, filters=filters)
        else:
            raise ValueError("Invalid mode: {!r}".format(mode))

        if isinstance(filename, (str, bytes)):
            if "b" not in mode:
                mode += "b"
            self._fp = builtins.open(filename, mode)
            self._closefp = True
            self._mode = mode_code
        elif hasattr(filename, "read") or hasattr(filename, "write"):
            self._fp = filename
            self._mode = mode_code
        else:
            raise TypeError("filename must be a str or bytes object, or a file")

    def close(self):
        """Flush and close the file.

        May be called more than once without error. Once the file is
        closed, any other operation on it will raise a ValueError.
        """
        if self._mode == _MODE_CLOSED:
            return
        try:
            if self._mode in (_MODE_READ, _MODE_READ_EOF):
                self._decompressor = None
                self._buffer = None
            elif self._mode == _MODE_WRITE:
                self._fp.write(self._compressor.flush())
                self._compressor = None
        finally:
            try:
                if self._closefp:
                    self._fp.close()
            finally:
                self._fp = None
                self._closefp = False
                self._mode = _MODE_CLOSED

    @property
    def closed(self):
        """True if this file is closed."""
        return self._mode == _MODE_CLOSED

    def fileno(self):
        """Return the file descriptor for the underlying file."""
        self._check_not_closed()
        return self._fp.fileno()

    def seekable(self):
        """Return whether the file supports seeking."""
        return self.readable() and self._fp.seekable()

    def readable(self):
        """Return whether the file was opened for reading."""
        self._check_not_closed()
        return self._mode in (_MODE_READ, _MODE_READ_EOF)

    def writable(self):
        """Return whether the file was opened for writing."""
        self._check_not_closed()
        return self._mode == _MODE_WRITE

    # Mode-checking helper functions.

    def _check_not_closed(self):
        if self.closed:
            raise ValueError("I/O operation on closed file")

    def _check_can_read(self):
        if not self.readable():
            raise io.UnsupportedOperation("File not open for reading")

    def _check_can_write(self):
        if not self.writable():
            raise io.UnsupportedOperation("File not open for writing")

    def _check_can_seek(self):
        if not self.readable():
            raise io.UnsupportedOperation("Seeking is only supported "
                                          "on files open for reading")
        if not self._fp.seekable():
            raise io.UnsupportedOperation("The underlying file object "
                                          "does not support seeking")

    # Fill the readahead buffer if it is empty. Returns False on EOF.
    def _fill_buffer(self):
        # Depending on the input data, our call to the decompressor may not
        # return any data. In this case, try again after reading another block.
        while True:
            if self._buffer:
                return True

            if self._decompressor.unused_data:
                rawblock = self._decompressor.unused_data
            else:
                rawblock = self._fp.read(_BUFFER_SIZE)

            if not rawblock:
                if self._decompressor.eof:
                    self._mode = _MODE_READ_EOF
                    self._size = self._pos
                    return False
                else:
                    raise EOFError("Compressed file ended before the "
                                   "end-of-stream marker was reached")

            # Continue to next stream.
            if self._decompressor.eof:
                self._decompressor = LZMADecompressor(**self._init_args)

            self._buffer = self._decompressor.decompress(rawblock)

    # Read data until EOF.
    # If return_data is false, consume the data without returning it.
    def _read_all(self, return_data=True):
        blocks = []
        while self._fill_buffer():
            if return_data:
                blocks.append(self._buffer)
            self._pos += len(self._buffer)
            self._buffer = None
        if return_data:
            return b"".join(blocks)

    # Read a block of up to n bytes.
    # If return_data is false, consume the data without returning it.
    def _read_block(self, n, return_data=True):
        blocks = []
        while n > 0 and self._fill_buffer():
            if n < len(self._buffer):
                data = self._buffer[:n]
                self._buffer = self._buffer[n:]
            else:
                data = self._buffer
                self._buffer = None
            if return_data:
                blocks.append(data)
            self._pos += len(data)
            n -= len(data)
        if return_data:
            return b"".join(blocks)

    def peek(self, size=-1):
        """Return buffered data without advancing the file position.

        Always returns at least one byte of data, unless at EOF.
        The exact number of bytes returned is unspecified.
        """
        self._check_can_read()
        if self._mode == _MODE_READ_EOF or not self._fill_buffer():
            return b""
        return self._buffer

    def read(self, size=-1):
        """Read up to size uncompressed bytes from the file.

        If size is negative or omitted, read until EOF is reached.
        Returns b"" if the file is already at EOF.
        """
        self._check_can_read()
        if self._mode == _MODE_READ_EOF or size == 0:
            return b""
        elif size < 0:
            return self._read_all()
        else:
            return self._read_block(size)

    def read1(self, size=-1):
        """Read up to size uncompressed bytes, while trying to avoid
        making multiple reads from the underlying stream.

        Returns b"" if the file is at EOF.
        """
        # Usually, read1() calls _fp.read() at most once. However, sometimes
        # this does not give enough data for the decompressor to make progress.
        # In this case we make multiple reads, to avoid returning b"".
        self._check_can_read()
        if (size == 0 or self._mode == _MODE_READ_EOF or
            not self._fill_buffer()):
            return b""
        if 0 < size < len(self._buffer):
            data = self._buffer[:size]
            self._buffer = self._buffer[size:]
        else:
            data = self._buffer
            self._buffer = None
        self._pos += len(data)
        return data

    def write(self, data):
        """Write a bytes object to the file.

        Returns the number of uncompressed bytes written, which is
        always len(data). Note that due to buffering, the file on disk
        may not reflect the data written until close() is called.
        """
        self._check_can_write()
        compressed = self._compressor.compress(data)
        self._fp.write(compressed)
        self._pos += len(data)
        return len(data)

    # Rewind the file to the beginning of the data stream.
    def _rewind(self):
        self._fp.seek(0, 0)
        self._mode = _MODE_READ
        self._pos = 0
        self._decompressor = LZMADecompressor(**self._init_args)
        self._buffer = None

    def seek(self, offset, whence=0):
        """Change the file position.

        The new position is specified by offset, relative to the
        position indicated by whence. Possible values for whence are:

            0: start of stream (default): offset must not be negative
            1: current stream position
            2: end of stream; offset must not be positive

        Returns the new file position.

        Note that seeking is emulated, sp depending on the parameters,
        this operation may be extremely slow.
        """
        self._check_can_seek()

        # Recalculate offset as an absolute file position.
        if whence == 0:
            pass
        elif whence == 1:
            offset = self._pos + offset
        elif whence == 2:
            # Seeking relative to EOF - we need to know the file's size.
            if self._size < 0:
                self._read_all(return_data=False)
            offset = self._size + offset
        else:
            raise ValueError("Invalid value for whence: {}".format(whence))

        # Make it so that offset is the number of bytes to skip forward.
        if offset < self._pos:
            self._rewind()
        else:
            offset -= self._pos

        # Read and discard data until we reach the desired position.
        if self._mode != _MODE_READ_EOF:
            self._read_block(offset, return_data=False)

        return self._pos

    def tell(self):
        """Return the current file position."""
        self._check_not_closed()
        return self._pos

def open(filename, mode="rb",
         format=None, check=-1, preset=None, filters=None,
         encoding=None, errors=None, newline=None):
    """Open an LZMA-compressed file in binary or text mode.

    filename can be either an actual file name (given as a str or bytes object),
    in which case the named file is opened, or it can be an existing file object
    to read from or write to.

    The mode argument can be "r", "rb" (default), "w", "wb", "a", or "ab" for
    binary mode, or "rt", "wt" or "at" for text mode.

    The format, check, preset and filters arguments specify the compression
    settings, as for LZMACompressor, LZMADecompressor and LZMAFile.

    For binary mode, this function is equivalent to the LZMAFile constructor:
    LZMAFile(filename, mode, ...). In this case, the encoding, errors and
    newline arguments must not be provided.

    For text mode, a LZMAFile object is created, and wrapped in an
    io.TextIOWrapper instance with the specified encoding, error handling
    behavior, and line ending(s).

    """
    if "t" in mode:
        if "b" in mode:
            raise ValueError("Invalid mode: %r" % (mode,))
    else:
        if encoding is not None:
            raise ValueError("Argument 'encoding' not supported in binary mode")
        if errors is not None:
            raise ValueError("Argument 'errors' not supported in binary mode")
        if newline is not None:
            raise ValueError("Argument 'newline' not supported in binary mode")

    lz_mode = mode.replace("t", "")
    binary_file = LZMAFile(filename, lz_mode, format=format, check=check,
                           preset=preset, filters=filters)

    if "t" in mode:
        return io.TextIOWrapper(binary_file, encoding, errors, newline)
    else:
        return binary_file

def compress(data, format=FORMAT_XZ, check=-1, preset=None, filters=None):
    """Compress a block of data.

    Refer to LZMACompressor's docstring for a description of the
    optional arguments *format*, *check*, *preset* and *filters*.

    For incremental compression, use an LZMACompressor object instead.
    """
    comp = LZMACompressor(format, check, preset, filters)
    return comp.compress(data) + comp.flush()

def decompress(data, format=FORMAT_AUTO, memlimit=None, filters=None):
    """Decompress a block of data.

    Refer to LZMADecompressor's docstring for a description of the
    optional arguments *format*, *check* and *filters*.

    For incremental decompression, use a LZMADecompressor object instead.
    """
    results = []
    while True:
        decomp = LZMADecompressor(format, memlimit, filters)
        results.append(decomp.decompress(data))
        if not decomp.eof:
            raise LZMAError("Compressed data ended before the "
                            "end-of-stream marker was reached")
        if not decomp.unused_data:
            return b"".join(results)
        # There is unused data left over. Proceed to next stream.
        data = decomp.unused_data
<|endoftext|>


<commit_before>import radical.utils as ru
from radical.entk.exceptions import *
from radical.entk.stage.stage import Stage
import threading
from radical.entk import states
from collections import Iterable

class Pipeline(object):

    """
    A pipeline represents a collection of objects that have a linear temporal
    execution order.  In this case, a pipeline consists of multiple 'Stage'
    objects. Each ```Stage_i``` can execute only after all stages up to
    ```Stage_(i-1)``` have completed execution.

    """

    def __init__(self):

        self._uid  = ru.generate_id('pipeline.%(counter)04d', ru.ID_CUSTOM)
        self._name = None

        self._stages = list()

        self._state = states.INITIAL

        # Keep track of states attained
        self._state_history = [states.INITIAL]

        # To keep track of current state
        self._stage_count = len(self._stages)
        self._cur_stage = 0

        # Lock around current stage
        self._lock = threading.Lock()

        # To keep track of termination of pipeline
        self._completed_flag = threading.Event()

    # --------------------------------------------------------------------------
    # Getter functions
    # --------------------------------------------------------------------------

    @property
    def name(self):
        """
        Name of the pipeline useful for bookkeeping and to refer to this pipeline while data staging.
        Do not use a ',' or '_' in an object's name.

        :getter: Returns the name of the pipeline
        :setter: Assigns the name of the pipeline
        :type: String
        """
        return self._name

    @property
    def stages(self):
        """
        Stages of the list

        :getter: Returns the stages in the current Pipeline
        :setter: Assigns the stages to the current Pipeline
        :type: List
        """

        return self._stages

    @property
    def state(self):
        """
        Current state of the pipeline

        :getter: Returns the state of the current pipeline
        :type: String
        """

        return self._state

    @property
    def uid(self):
        """
        Unique ID of the current pipeline

        :getter: Returns the unique id of the current pipeline
        :type: String
        """
        return self._uid

    @property
    def luid(self):
        """
        Unique ID of the current pipeline (fully qualified).
        For the pipeline class, his is an alias to `uid`.

        example:
            >>> pipeline.luid
            pipe.0001

        :getter: Returns the fully qualified uid of the current pipeline
        :type: String
        """
        if self.name: return self.name
        else        : return self.uid

    @property
    def lock(self):
        """
        Returns the lock over the current Pipeline

        :return: Lock object
        """

        return self._lock

    @property
    def completed(self):
        """
        Returns whether the Pipeline has completed

        :return: Boolean
        """
        return self._completed_flag.is_set()

    @property
    def current_stage(self):
        """
        Returns the current stage being executed

        :return: Integer
        """

        return self._cur_stage

    @property
    def state_history(self):
        """
        Returns a list of the states obtained in temporal order

        :return: list
        """

        return self._state_history

    # ------------------------------------------------------------------------------------------------------------------
    # Setter functions
    # ------------------------------------------------------------------------------------------------------------------

    @name.setter
    def name(self, value):
        if isinstance(value, str):
            if ',' in value:
                raise ValueError(obj=self._uid,
                                attribute='name',
                                actual_value=value,
                                expected_value="Using ',' in an object's name will corrupt the profiling and internal mapping tables")
            else:
                self._name = value

        else:
            raise TypeError(expected_type=str, actual_type=type(value))

    @stages.setter
    def stages(self, value):

        self._stages = self._validate_entities(value)

        self._stage_count = len(self._stages)
        if self._cur_stage == 0:
            self._cur_stage = 1

    @state.setter
    def state(self, value):
        if isinstance(value, str):
            if value in list(states._pipeline_state_values.keys()):
                self._state = value

                # We add SUSPENDED to state history in suspend()
                if self._state != states.SUSPENDED:
                    self._state_history.append(value)
            else:
                raise ValueError(obj=self._uid,
                                 attribute='state',
                                 expected_value=list(states._pipeline_state_values.keys()),
                                 actual_value=value)
        else:
            raise TypeError(expected_type=str, actual_type=type(value))

    # --------------------------------------------------------------------------
    #
    def add_stages(self, value):
        """
        Appends stages to the current Pipeline

        :argument: List of Stage objects
        """
        stages = self._validate_entities(value)

        self._stages.extend(stages)
        self._stage_count = len(self._stages)
        if self._cur_stage == 0:
            self._cur_stage = 1

        for stage in stages:
            stage.parent_pipeline['uid']  = self._uid
            stage.parent_pipeline['name'] = self._name

            for task in stage.tasks:
                task.parent_pipeline['uid']  = self._uid
                task.parent_pipeline['name'] = self._name

    def to_dict(self):
        """
        Convert current Pipeline (i.e. its attributes) into a dictionary

        :return: python dictionary
        """

        pipeline_desc_as_dict = {

            'uid': self._uid,
            'name': self._name,
            'state': self._state,
            'state_history': self._state_history,
            'completed': self._completed_flag.is_set()
        }

        return pipeline_desc_as_dict

    def from_dict(self, d):
        """
        Create a Pipeline from a dictionary. The change is in inplace.

        :argument: python dictionary
        :return: None
        """

        if 'uid' in d:
            if d['uid']:
                self._uid = d['uid']

        if 'name' in d:
            if d['name']:
                self._name = d['name']

        if 'state' in d:
            if isinstance(d['state'], str) or isinstance(d['state'], str):
                if d['state'] in list(states._pipeline_state_values.keys()):
                    self._state = d['state']
                else:
                    raise ValueError(obj=self._uid,
                                     attribute='state',
                                     expected_value=list(states._pipeline_state_values.keys()),
                                     actual_value=d['state'])
            else:
                raise TypeError(entity='state', expected_type=str,
                                actual_type=type(d['state']))

        else:
            self._state = states.INITIAL

        if 'state_history' in d:
            if isinstance(d['state_history'], list):
                self._state_history = d['state_history']
            else:
                raise TypeError(entity='state_history', expected_type=list, actual_type=type(
                    d['state_history']))

        if 'completed' in d:
            if isinstance(d['completed'], bool):
                if d['completed']:
                    self._completed_flag.set()
            else:
                raise TypeError(entity='completed', expected_type=bool,
                                actual_type=type(d['completed']))

    # --------------------------------------------------------------------------
    #
    def suspend(self):
        '''
        Pause execution of the pipeline: stages and tasks that are executing
        will continue to execute, but no new stages and tasks will be eligible
        for execution until `resume()` is called.

         - The `suspend()` method can not be called on a suspended or completed
           pipeline, doing so will result in an exeption.
         - The state of the pipeline will be set to `SUSPENDED`.
        '''
        if self._state == states.SUSPENDED:
            raise EnTKError(
                'suspend() called on Pipeline %s that is already suspended' % self._uid)

        self._state = states.SUSPENDED
        self._state_history.append(self._state)

    # --------------------------------------------------------------------------
    #
    def resume(self):
        '''
        Continue execution of paused stages and tasks.

         - The `resume()` method can only be called on a suspended pipeline, an
           exception will be raised if that condition is not met.
         - The state of a resumed pipeline will be set to the state the pipeline
           had before suspension.
        '''
        if self._state != states.SUSPENDED:
            raise EnTKError('Cannot resume Pipeline %s: not suspended [%s] [%s]'
                    % (self._uid, self._state, self._state_history))

        self._state = self._state_history[-2]
        self._state_history.append(self._state)

    # --------------------------------------------------------------------------
    # Private methods
    # --------------------------------------------------------------------------

    def _increment_stage(self):
        """
        Purpose: Increment stage pointer. Also check if Pipeline has completed.
        """

        try:

            if self._cur_stage < self._stage_count:
                self._cur_stage += 1
            else:
                self._completed_flag.set()

        except Exception as ex:
            raise EnTKError(text=ex)

    def _decrement_stage(self):
        """
        Purpose: Decrement stage pointer. Reset completed flag.
        """

        try:

            if self._cur_stage > 0:
                self._cur_stage -= 1
                self._completed_flag = threading.Event()  # reset

        except Exception as ex:
            raise EnTKError(text=ex)

    @classmethod
    def _validate_entities(self, stages):
        """
        Purpose: Validate whether the argument 'stages' is of list of Stage objects

        :argument: list of Stage objects
        """
        if not stages:
            raise TypeError(expected_type=Stage, actual_type=type(stages))

        if not isinstance(stages, list):
            stages = [stages]

        for value in stages:
            if not isinstance(value, Stage):
                raise TypeError(expected_type=Stage, actual_type=type(value))

        return stages

    def _validate(self):
        """
        Purpose: Validate that the state of the current Pipeline is 'DESCRIBED' (user has not meddled with it). Also
        validate that the current Pipeline contains Stages.
        """

        if self._state is not states.INITIAL:

            raise ValueError(obj=self._uid,
                             attribute='state',
                             expected_value=states.INITIAL,
                             actual_value=self._state)

        if not self._stages:

            raise MissingError(obj=self._uid,
                               missing_attribute='stages')

        for stage in self._stages:
            stage._validate()

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

<commit_msg>Fix warning regarding ABC import from collections<commit_after>import radical.utils as ru
from radical.entk.exceptions import *
from radical.entk.stage.stage import Stage
import threading
from radical.entk import states
from collections.abc import Iterable

class Pipeline(object):

    """
    A pipeline represents a collection of objects that have a linear temporal
    execution order.  In this case, a pipeline consists of multiple 'Stage'
    objects. Each ```Stage_i``` can execute only after all stages up to
    ```Stage_(i-1)``` have completed execution.

    """

    def __init__(self):

        self._uid  = ru.generate_id('pipeline.%(counter)04d', ru.ID_CUSTOM)
        self._name = None

        self._stages = list()

        self._state = states.INITIAL

        # Keep track of states attained
        self._state_history = [states.INITIAL]

        # To keep track of current state
        self._stage_count = len(self._stages)
        self._cur_stage = 0

        # Lock around current stage
        self._lock = threading.Lock()

        # To keep track of termination of pipeline
        self._completed_flag = threading.Event()

    # --------------------------------------------------------------------------
    # Getter functions
    # --------------------------------------------------------------------------

    @property
    def name(self):
        """
        Name of the pipeline useful for bookkeeping and to refer to this pipeline while data staging.
        Do not use a ',' or '_' in an object's name.

        :getter: Returns the name of the pipeline
        :setter: Assigns the name of the pipeline
        :type: String
        """
        return self._name

    @property
    def stages(self):
        """
        Stages of the list

        :getter: Returns the stages in the current Pipeline
        :setter: Assigns the stages to the current Pipeline
        :type: List
        """

        return self._stages

    @property
    def state(self):
        """
        Current state of the pipeline

        :getter: Returns the state of the current pipeline
        :type: String
        """

        return self._state

    @property
    def uid(self):
        """
        Unique ID of the current pipeline

        :getter: Returns the unique id of the current pipeline
        :type: String
        """
        return self._uid

    @property
    def luid(self):
        """
        Unique ID of the current pipeline (fully qualified).
        For the pipeline class, his is an alias to `uid`.

        example:
            >>> pipeline.luid
            pipe.0001

        :getter: Returns the fully qualified uid of the current pipeline
        :type: String
        """
        if self.name: return self.name
        else        : return self.uid

    @property
    def lock(self):
        """
        Returns the lock over the current Pipeline

        :return: Lock object
        """

        return self._lock

    @property
    def completed(self):
        """
        Returns whether the Pipeline has completed

        :return: Boolean
        """
        return self._completed_flag.is_set()

    @property
    def current_stage(self):
        """
        Returns the current stage being executed

        :return: Integer
        """

        return self._cur_stage

    @property
    def state_history(self):
        """
        Returns a list of the states obtained in temporal order

        :return: list
        """

        return self._state_history

    # ------------------------------------------------------------------------------------------------------------------
    # Setter functions
    # ------------------------------------------------------------------------------------------------------------------

    @name.setter
    def name(self, value):
        if isinstance(value, str):
            if ',' in value:
                raise ValueError(obj=self._uid,
                                attribute='name',
                                actual_value=value,
                                expected_value="Using ',' in an object's name will corrupt the profiling and internal mapping tables")
            else:
                self._name = value

        else:
            raise TypeError(expected_type=str, actual_type=type(value))

    @stages.setter
    def stages(self, value):

        self._stages = self._validate_entities(value)

        self._stage_count = len(self._stages)
        if self._cur_stage == 0:
            self._cur_stage = 1

    @state.setter
    def state(self, value):
        if isinstance(value, str):
            if value in list(states._pipeline_state_values.keys()):
                self._state = value

                # We add SUSPENDED to state history in suspend()
                if self._state != states.SUSPENDED:
                    self._state_history.append(value)
            else:
                raise ValueError(obj=self._uid,
                                 attribute='state',
                                 expected_value=list(states._pipeline_state_values.keys()),
                                 actual_value=value)
        else:
            raise TypeError(expected_type=str, actual_type=type(value))

    # --------------------------------------------------------------------------
    #
    def add_stages(self, value):
        """
        Appends stages to the current Pipeline

        :argument: List of Stage objects
        """
        stages = self._validate_entities(value)

        self._stages.extend(stages)
        self._stage_count = len(self._stages)
        if self._cur_stage == 0:
            self._cur_stage = 1

        for stage in stages:
            stage.parent_pipeline['uid']  = self._uid
            stage.parent_pipeline['name'] = self._name

            for task in stage.tasks:
                task.parent_pipeline['uid']  = self._uid
                task.parent_pipeline['name'] = self._name

    def to_dict(self):
        """
        Convert current Pipeline (i.e. its attributes) into a dictionary

        :return: python dictionary
        """

        pipeline_desc_as_dict = {

            'uid': self._uid,
            'name': self._name,
            'state': self._state,
            'state_history': self._state_history,
            'completed': self._completed_flag.is_set()
        }

        return pipeline_desc_as_dict

    def from_dict(self, d):
        """
        Create a Pipeline from a dictionary. The change is in inplace.

        :argument: python dictionary
        :return: None
        """

        if 'uid' in d:
            if d['uid']:
                self._uid = d['uid']

        if 'name' in d:
            if d['name']:
                self._name = d['name']

        if 'state' in d:
            if isinstance(d['state'], str) or isinstance(d['state'], str):
                if d['state'] in list(states._pipeline_state_values.keys()):
                    self._state = d['state']
                else:
                    raise ValueError(obj=self._uid,
                                     attribute='state',
                                     expected_value=list(states._pipeline_state_values.keys()),
                                     actual_value=d['state'])
            else:
                raise TypeError(entity='state', expected_type=str,
                                actual_type=type(d['state']))

        else:
            self._state = states.INITIAL

        if 'state_history' in d:
            if isinstance(d['state_history'], list):
                self._state_history = d['state_history']
            else:
                raise TypeError(entity='state_history', expected_type=list, actual_type=type(
                    d['state_history']))

        if 'completed' in d:
            if isinstance(d['completed'], bool):
                if d['completed']:
                    self._completed_flag.set()
            else:
                raise TypeError(entity='completed', expected_type=bool,
                                actual_type=type(d['completed']))

    # --------------------------------------------------------------------------
    #
    def suspend(self):
        '''
        Pause execution of the pipeline: stages and tasks that are executing
        will continue to execute, but no new stages and tasks will be eligible
        for execution until `resume()` is called.

         - The `suspend()` method can not be called on a suspended or completed
           pipeline, doing so will result in an exeption.
         - The state of the pipeline will be set to `SUSPENDED`.
        '''
        if self._state == states.SUSPENDED:
            raise EnTKError(
                'suspend() called on Pipeline %s that is already suspended' % self._uid)

        self._state = states.SUSPENDED
        self._state_history.append(self._state)

    # --------------------------------------------------------------------------
    #
    def resume(self):
        '''
        Continue execution of paused stages and tasks.

         - The `resume()` method can only be called on a suspended pipeline, an
           exception will be raised if that condition is not met.
         - The state of a resumed pipeline will be set to the state the pipeline
           had before suspension.
        '''
        if self._state != states.SUSPENDED:
            raise EnTKError('Cannot resume Pipeline %s: not suspended [%s] [%s]'
                    % (self._uid, self._state, self._state_history))

        self._state = self._state_history[-2]
        self._state_history.append(self._state)

    # --------------------------------------------------------------------------
    # Private methods
    # --------------------------------------------------------------------------

    def _increment_stage(self):
        """
        Purpose: Increment stage pointer. Also check if Pipeline has completed.
        """

        try:

            if self._cur_stage < self._stage_count:
                self._cur_stage += 1
            else:
                self._completed_flag.set()

        except Exception as ex:
            raise EnTKError(text=ex)

    def _decrement_stage(self):
        """
        Purpose: Decrement stage pointer. Reset completed flag.
        """

        try:

            if self._cur_stage > 0:
                self._cur_stage -= 1
                self._completed_flag = threading.Event()  # reset

        except Exception as ex:
            raise EnTKError(text=ex)

    @classmethod
    def _validate_entities(self, stages):
        """
        Purpose: Validate whether the argument 'stages' is of list of Stage objects

        :argument: list of Stage objects
        """
        if not stages:
            raise TypeError(expected_type=Stage, actual_type=type(stages))

        if not isinstance(stages, list):
            stages = [stages]

        for value in stages:
            if not isinstance(value, Stage):
                raise TypeError(expected_type=Stage, actual_type=type(value))

        return stages

    def _validate(self):
        """
        Purpose: Validate that the state of the current Pipeline is 'DESCRIBED' (user has not meddled with it). Also
        validate that the current Pipeline contains Stages.
        """

        if self._state is not states.INITIAL:

            raise ValueError(obj=self._uid,
                             attribute='state',
                             expected_value=states.INITIAL,
                             actual_value=self._state)

        if not self._stages:

            raise MissingError(obj=self._uid,
                               missing_attribute='stages')

        for stage in self._stages:
            stage._validate()

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

<|endoftext|>


<commit_before># -*- coding: utf-8 -*- vim:encoding=utf-8:
# vim: tabstop=4:shiftwidth=4:softtabstop=4:expandtab

# Copyright © 2010-2012 Greek Research and Technology Network (GRNET S.A.)
#
# Permission to use, copy, modify, and/or distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH REGARD
# TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
# FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT,
# OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
# USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
# TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
# OF THIS SOFTWARE.

import unittest
from hwdoc.models import Vendor,Model,Equipment, ServerManagement
from hwdoc.functions import search

class EquipmentTestCase(unittest.TestCase):
    def setUp(self):
        self.vendor = Vendor.objects.create(name='HP')
        self.model1 = Model.objects.create(vendor=self.vendor, name='DL 385 G7', u=2)
        self.model2 = Model.objects.create(vendor=self.vendor, name='DL 380 G7', u=2)

        self.server1 = Equipment.objects.create(
                                model = self.model1,
                                serial = '123456',
                                rack = '10',
                                unit = '20',
                                purpose = 'Nothing',
                            )

        self.server2 = Equipment.objects.create(
                                model = self.model2,
                                serial = '123457',
                                rack = '10',
                                unit = '22',
                                purpose = 'Nothing',
                            )

        self.management = ServerManagement.objects.create (
                            equipment = self.server2,
                            method = 'dummy',
                            hostname = 'example.com',
                            )

    def tearDown(self):
        Equipment.objects.all().delete()
        Model.objects.all().delete()
        Vendor.objects.all().delete()

    # Tests start here
    def test_if_servers_in_same_rack(self):
        self.assertEqual(self.server1.rack, self.server2.rack)

    def test_dummy_management_fuctions(self):
        self.assertTrue(self.management.power_on())
        self.assertTrue(self.management.power_off())
        self.assertTrue(self.management.power_cycle())
        self.assertTrue(self.management.power_reset())
        self.assertTrue(self.management.power_off_acpi())
        self.assertTrue(self.management.pass_change(**{'change_username': 'me', 'newpass': 'us'}))
        self.assertTrue(self.management.set_settings())
        self.assertTrue(self.management.set_ldap_settings())
        self.assertTrue(self.management.boot_order())
        self.assertTrue(self.management.license_set())
        self.assertTrue(self.management.bmc_reset())
        self.assertTrue(self.management.bmc_factory_defaults())

    def test_equipment_number(self):
        self.assertEqual(Equipment.objects.all().count(), 2)

    def test_search_empty(self):
        self.assertFalse(search(''))

    def test_search_rack(self):
        self.assertEqual(search(self.server1.rack).count(), 2)

    def test_search_serial(self):
        self.assertEqual(search(self.server1.serial)[0].serial, self.server1.serial)

<commit_msg>hwdoc testing suite updates<commit_after># -*- coding: utf-8 -*- vim:encoding=utf-8:
# vim: tabstop=4:shiftwidth=4:softtabstop=4:expandtab

# Copyright © 2010-2012 Greek Research and Technology Network (GRNET S.A.)
#
# Permission to use, copy, modify, and/or distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH REGARD
# TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
# FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT,
# OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
# USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
# TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
# OF THIS SOFTWARE.

import unittest
from hwdoc.models import Vendor, Model, Equipment, ServerManagement
from hwdoc.functions import search, get_search_terms

class EquipmentTestCase(unittest.TestCase):
    def setUp(self):
        self.vendor = Vendor.objects.create(name='HP')
        self.model1 = Model.objects.create(vendor=self.vendor, name='DL 385 G7', u=2)
        self.model2 = Model.objects.create(vendor=self.vendor, name='DL 380 G7', u=2)
        self.model2 = Model.objects.create(vendor=self.vendor, name='Fujisu PRIMERGY 200 S', u=1)

        self.server1 = Equipment.objects.create(
                                model = self.model1,
                                serial = 'G123456',
                                rack = '10',
                                unit = '20',
                                purpose = 'Nothing',
                            )

        self.server2 = Equipment.objects.create(
                                model = self.model2,
                                serial = 'R123457',
                                rack = '10',
                                unit = '22',
                                purpose = 'Nothing',
                            )

        self.management = ServerManagement.objects.create (
                            equipment = self.server2,
                            method = 'dummy',
                            hostname = 'example.com',
                            )

    def tearDown(self):
        ServerManagement.objects.all().delete()
        Equipment.objects.all().delete()
        Model.objects.all().delete()
        Vendor.objects.all().delete()

    # Tests start here
    def test_if_servers_in_same_rack(self):
        self.assertEqual(self.server1.rack, self.server2.rack)

    def test_dummy_management_fuctions(self):
        self.assertTrue(self.management.power_on())
        self.assertTrue(self.management.power_off())
        self.assertTrue(self.management.power_cycle())
        self.assertTrue(self.management.power_reset())
        self.assertTrue(self.management.power_off_acpi())
        self.assertTrue(self.management.pass_change(**{'change_username': 'me', 'newpass': 'us'}))
        self.assertTrue(self.management.set_settings())
        self.assertTrue(self.management.set_ldap_settings())
        self.assertTrue(self.management.boot_order())
        self.assertTrue(self.management.license_set())
        self.assertTrue(self.management.bmc_reset())
        self.assertTrue(self.management.bmc_factory_defaults())

    def test_equipment_number(self):
        self.assertEqual(Equipment.objects.all().count(), 2)

    def test_search_empty(self):
        self.assertFalse(search(''))

    def test_search_rack(self):
        self.assertEqual(search(self.server1.rack).count(), 2)

    def test_search_serial(self):
        self.assertEqual(search(self.server1.serial)[0].serial, self.server1.serial)
        self.assertEqual(search(self.server2.serial)[0].serial, self.server2.serial)

    def test_free_text_search(self):
        text=u'''
        This is a text that is not going to make any sense apart from containing
        a hostname for a server (aka example.com) and a rackunit aka R10U22
        '''

        tokens = get_search_terms(text)
        self.assertNotEqual(search(tokens).count(), 0)

<|endoftext|>


<commit_before>from . import *

from pymsgbox.native import confirm
from kivy.config import Config
from kivy.core.window import Window

from kivy.app import App
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.widget import Widget
from kivy.clock import Clock

from kivy.core.image import Image
from kivy.graphics import Rectangle, Rotate

from kivy.uix.behaviors import ButtonBehavior

from kivy.properties import DictProperty, NumericProperty

Window.size = (738, 399)
Window.clearcolor = (1, 1, 1, 1)
Config.set('graphics', 'resizable', False)

class DurakAtlas(Widget):
    sprite = DictProperty()
    sheet = Image('spritesheet.png')
    sheet_width, sheet_height = sheet.size

    cw = NumericProperty(sheet_width // len(deck.ranks))
    ch = NumericProperty(sheet_height // (len(deck.suits) + 1))

    def __init__(self, **kwargs):
        super(DurakAtlas, self).__init__(**kwargs)

        texture = self.sheet.texture

        x = y = 0

        self.sprite['service'] = {}
        self.sprite['service']['back'] = texture.get_region(0, 0, self.cw, self.ch)
        self.sprite['service']['button'] = texture.get_region(79, 0, self.cw, self.ch)
        for s in deck.suits:
            self.sprite[s] = {}
            x = 0
            y += self.ch
            for r in deck.ranks:
                self.sprite[s][r] = texture.get_region(x, y, self.cw, self.ch)
                x += self.cw

atlas = DurakAtlas()

class CardSprite(ButtonBehavior, Widget):
    def __init__(self, x, y, card, angle=0):
        super(CardSprite, self).__init__()

        self.card = card
        self.texture = atlas.sprite[card[1]][card[0]]

        self.pos = x, y
        self.size_hint = (None, None)
        self.size = (atlas.cw, atlas.ch)
        self.angle = angle

        with self.canvas:
            Rotate(angle=self.angle,
                   origin=self.center)

            self.sprite = Rectangle(pos=self.pos,
                                    size=self.size,
                                    texture=self.texture)

            Rotate(angle=-self.angle,
                   origin=self.center)

    def on_press(self):
        if self.card in player.hand:
            try:
                move = player.hand.index(self.card)

                if player.moving:
                    table_ranks = [card[0] for card in deck.table]

                    if not player.throwing:
                        player.throwing = True
                    elif not player.hand[move][0] in table_ranks:
                        raise MoveError('[ERROR] Эту карту нельзя подкинуть ни к одной на столе')

                else:
                    if opponent.move[1] != player.hand[move][1] != deck.trump[1]:
                        raise MoveError('[ERROR] Бьющая карта должна быть той же масти или козырем')
                    if deck.order(player.hand[move]) < deck.order(opponent.move):
                        raise MoveError('[ERROR] Бьющая карта должна быть старше побиваемой')

                player.move = player.hand.pop(move)
                deck.table.append(player.move)

                if player.hand and opponent.hand and len(deck.table) <= 12:
                    opponent.make_move()

            except MoveError as ErrorMessage:
                print(ErrorMessage)

        elif self.card == ('button', 'service'):
            try:
                if player.moving:
                    if not player.throwing:
                        raise ValueError

                    player.moving = False
                    player.throwing = False

                    player.fill_hand()
                    opponent.fill_hand()

                elif not player.moving:
                    player.hand += deck.table

                    opponent.fill_hand()
                    player.fill_hand()

                deck.table = []
                opponent.make_move()

            except ValueError:
                print('[ERROR] Вы должны выбрать карту на первом ходе')

        Clock.schedule_once(game.update, 0)

class DurakGame(FloatLayout):
    def update(self, dt):
        player.hand = sorted(player.hand, key=deck.order)
        opponent.hand = sorted(opponent.hand, key=deck.order)

        self.clear_widgets()

        self.add_widget(CardSprite(32, 5, ('button', 'service')))

        x = 144
        for card in player.hand:
            self.add_widget(CardSprite(x, 5, card))
            cards_amount = len(player.hand)
            x += 495 // ((cards_amount - 1) if cards_amount >= 4 else 3)

        x = 144
        for card in opponent.hand:
            self.add_widget(CardSprite(x, 271, ('back', 'service')))
            cards_amount = len(opponent.hand)
            x += 495 // ((cards_amount - 1) if cards_amount >= 4 else 3)

        for c in range(len(deck.table)):
            x = ((99 if c % 2 == 0 else 114) + (c // 2) * 99) + 45
            self.add_widget(CardSprite(x, 138, deck.table[c]), len(deck.table) - c)

        if deck.deck:
            if len(deck.deck) > 1:
                first_card = deck.last_card - 3 * (len(deck.deck) // 9 + 1)
                for x in range(first_card, deck.last_card, 3):
                    self.add_widget(CardSprite(x, 138, ('back', 'service')), x)
            self.add_widget(CardSprite(33, 138, deck.trump, 90), x + 1)

        if len(deck.table) == 12:
            player.fill_hand()
            opponent.fill_hand()
            deck.table = []

            Clock.schedule_once(self.update, 1)

        if not player.hand or not opponent.hand and not deck.deck:
            Clock.schedule_once(self.over)

    def first_state(self):
        player.hand = sorted(player.hand, key=deck.order)
        opponent.hand = sorted(opponent.hand, key=deck.order)

        self.clear_widgets()

        x = 45
        for card in player.hand:
            x += 99
            if card == player.trump:
                self.add_widget(CardSprite(x, 5, card))
            else:
                self.add_widget(CardSprite(x, 5, ('back', 'service')))

        x = 45
        for card in opponent.hand:
            x += 99
            if card == opponent.trump:
                self.add_widget(CardSprite(x, 271, card))
            else:
                self.add_widget(CardSprite(x, 271, ('back', 'service')))

        if deck.deck:
            if len(deck.deck) > 1:
                first_card = deck.last_card - 3 * (len(deck.deck) // 9 + 1)
                for x in range(first_card, deck.last_card, 3):
                    self.add_widget(CardSprite(x, 138, ('back', 'service')), x)
            self.add_widget(CardSprite(33, 138, deck.trump, 90), x + 1)

    def over(self, dt):
        if not player.hand and not opponent.hand:
            message = 'Ничья!'
        elif not player.hand:
            message = 'Вы победили!'
        else:
            message = 'Вы проиграли...'
        title = 'Игра окончена'
        buttons = ('Сыграть ещё раз', 'Выйти из игры')

        answer = confirm(message, title, buttons)
        if answer == buttons[0]:
            deck.__init__()
            opponent.__init__()
            player.__init__()
            app.run()
        else:
            app.stop()

game = DurakGame()

class DurakApp(App):
    def build(self):
        self.icon = 'icon.png'

        deck.shuffle()

        for c in range(6):
            player.take_card()
            opponent.take_card()

        deck.last_card = 5 + 3 * (len(deck.deck) // 9 + 1)

        deck.trump = deck.take()
        deck.deck.append(deck.trump)
        deck.suits.remove(deck.trump[1])
        deck.suits.append(deck.trump[1])

        player.trump = None
        opponent.trump = None

        for c in range(6):
            if player.hand[c][1] == deck.trump[1]:
                if not player.trump or deck.order(player.hand[c]) < deck.order(player.trump):
                    player.trump = player.hand[c]

            if opponent.hand[c][1] == deck.trump[1]:
                if not opponent.trump or deck.order(opponent.hand[c]) < deck.order(opponent.trump):
                    opponent.trump = opponent.hand[c]

        if player.trump and opponent.trump:
            if deck.order(player.trump) < deck.order(opponent.trump):
                player.moving = True
            else:
                player.moving = False
        elif player.trump:
            player.moving = True
        elif opponent.trump:
            player.moving = False
        else:
            player.moving = random.randint(0, 1)

        deck.table = []

        game.first_state()

        if not player.moving:
            opponent.make_move()

        Clock.schedule_once(game.update, 2)
        return game

app = DurakApp()

if __name__ == "__main__":
    app.run()
<commit_msg>fixed impossibility of draw<commit_after>from . import *

from pymsgbox.native import confirm
from kivy.config import Config
from kivy.core.window import Window

from kivy.app import App
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.widget import Widget
from kivy.clock import Clock

from kivy.core.image import Image
from kivy.graphics import Rectangle, Rotate

from kivy.uix.behaviors import ButtonBehavior

from kivy.properties import DictProperty, NumericProperty

Window.size = (738, 399)
Window.clearcolor = (1, 1, 1, 1)
Config.set('graphics', 'resizable', False)

class DurakAtlas(Widget):
    sprite = DictProperty()
    sheet = Image('spritesheet.png')
    sheet_width, sheet_height = sheet.size

    cw = NumericProperty(sheet_width // len(deck.ranks))
    ch = NumericProperty(sheet_height // (len(deck.suits) + 1))

    def __init__(self, **kwargs):
        super(DurakAtlas, self).__init__(**kwargs)

        texture = self.sheet.texture

        x = y = 0

        self.sprite['service'] = {}
        self.sprite['service']['back'] = texture.get_region(0, 0, self.cw, self.ch)
        self.sprite['service']['button'] = texture.get_region(79, 0, self.cw, self.ch)
        for s in deck.suits:
            self.sprite[s] = {}
            x = 0
            y += self.ch
            for r in deck.ranks:
                self.sprite[s][r] = texture.get_region(x, y, self.cw, self.ch)
                x += self.cw

atlas = DurakAtlas()

class CardSprite(ButtonBehavior, Widget):
    def __init__(self, x, y, card, angle=0):
        super(CardSprite, self).__init__()

        self.card = card
        self.texture = atlas.sprite[card[1]][card[0]]

        self.pos = x, y
        self.size_hint = (None, None)
        self.size = (atlas.cw, atlas.ch)
        self.angle = angle

        with self.canvas:
            Rotate(angle=self.angle,
                   origin=self.center)

            self.sprite = Rectangle(pos=self.pos,
                                    size=self.size,
                                    texture=self.texture)

            Rotate(angle=-self.angle,
                   origin=self.center)

    def on_press(self):
        if self.card in player.hand:
            try:
                move = player.hand.index(self.card)

                if player.moving:
                    table_ranks = [card[0] for card in deck.table]

                    if not player.throwing:
                        player.throwing = True
                    elif not player.hand[move][0] in table_ranks:
                        raise MoveError('[ERROR] Эту карту нельзя подкинуть ни к одной на столе')

                else:
                    if opponent.move[1] != player.hand[move][1] != deck.trump[1]:
                        raise MoveError('[ERROR] Бьющая карта должна быть той же масти или козырем')
                    if deck.order(player.hand[move]) < deck.order(opponent.move):
                        raise MoveError('[ERROR] Бьющая карта должна быть старше побиваемой')

                player.move = player.hand.pop(move)
                deck.table.append(player.move)

                if deck.deck or (player.hand or len(opponent.hand) == 1) and len(deck.table) <= 12:
                    opponent.make_move()

            except MoveError as ErrorMessage:
                print(ErrorMessage)

        elif self.card == ('button', 'service'):
            try:
                if player.moving:
                    if not player.throwing:
                        raise ValueError

                    player.moving = False
                    player.throwing = False

                    player.fill_hand()
                    opponent.fill_hand()

                elif not player.moving:
                    player.hand += deck.table

                    opponent.fill_hand()
                    player.fill_hand()

                deck.table = []
                opponent.make_move()

            except ValueError:
                print('[ERROR] Вы должны выбрать карту на первом ходе')

        Clock.schedule_once(game.update, 0)

class DurakGame(FloatLayout):
    def update(self, dt):
        player.hand = sorted(player.hand, key=deck.order)
        opponent.hand = sorted(opponent.hand, key=deck.order)

        self.clear_widgets()

        self.add_widget(CardSprite(32, 5, ('button', 'service')))

        x = 144
        for card in player.hand:
            self.add_widget(CardSprite(x, 5, card))
            cards_amount = len(player.hand)
            x += 495 // ((cards_amount - 1) if cards_amount >= 4 else 3)

        x = 144
        for card in opponent.hand:
            self.add_widget(CardSprite(x, 271, ('back', 'service')))
            cards_amount = len(opponent.hand)
            x += 495 // ((cards_amount - 1) if cards_amount >= 4 else 3)

        for c in range(len(deck.table)):
            x = ((99 if c % 2 == 0 else 114) + (c // 2) * 99) + 45
            self.add_widget(CardSprite(x, 138, deck.table[c]), len(deck.table) - c)

        if deck.deck:
            if len(deck.deck) > 1:
                first_card = deck.last_card - 3 * (len(deck.deck) // 9 + 1)
                for x in range(first_card, deck.last_card, 3):
                    self.add_widget(CardSprite(x, 138, ('back', 'service')), x)
            self.add_widget(CardSprite(33, 138, deck.trump, 90), x + 1)

        if len(deck.table) == 12:
            player.fill_hand()
            opponent.fill_hand()
            deck.table = []

            Clock.schedule_once(self.update, 1)

        if not deck.deck and \
           ((not opponent.hand and len(player.hand) > 1) or (not player.hand and len(opponent.hand) > 1)):

            Clock.schedule_once(self.over)

    def first_state(self):
        player.hand = sorted(player.hand, key=deck.order)
        opponent.hand = sorted(opponent.hand, key=deck.order)

        self.clear_widgets()

        x = 45
        for card in player.hand:
            x += 99
            if card == player.trump:
                self.add_widget(CardSprite(x, 5, card))
            else:
                self.add_widget(CardSprite(x, 5, ('back', 'service')))

        x = 45
        for card in opponent.hand:
            x += 99
            if card == opponent.trump:
                self.add_widget(CardSprite(x, 271, card))
            else:
                self.add_widget(CardSprite(x, 271, ('back', 'service')))

        if deck.deck:
            if len(deck.deck) > 1:
                first_card = deck.last_card - 3 * (len(deck.deck) // 9 + 1)
                for x in range(first_card, deck.last_card, 3):
                    self.add_widget(CardSprite(x, 138, ('back', 'service')), x)
            self.add_widget(CardSprite(33, 138, deck.trump, 90), x + 1)

    def over(self, dt):
        if not player.hand and not opponent.hand:
            message = 'Ничья!'
        elif not player.hand:
            message = 'Вы победили!'
        else:
            message = 'Вы проиграли...'
        title = 'Игра окончена'
        buttons = ('Сыграть ещё раз', 'Выйти из игры')

        answer = confirm(message, title, buttons)
        if answer == buttons[0]:
            deck.__init__()
            opponent.__init__()
            player.__init__()
            app.run()
        else:
            app.stop()

game = DurakGame()

class DurakApp(App):
    def build(self):
        self.icon = 'icon.png'

        deck.shuffle()

        for c in range(6):
            player.take_card()
            opponent.take_card()

        deck.last_card = 5 + 3 * (len(deck.deck) // 9 + 1)

        deck.trump = deck.take()
        deck.deck.append(deck.trump)
        deck.suits.remove(deck.trump[1])
        deck.suits.append(deck.trump[1])

        player.trump = None
        opponent.trump = None

        for c in range(6):
            if player.hand[c][1] == deck.trump[1]:
                if not player.trump or deck.order(player.hand[c]) < deck.order(player.trump):
                    player.trump = player.hand[c]

            if opponent.hand[c][1] == deck.trump[1]:
                if not opponent.trump or deck.order(opponent.hand[c]) < deck.order(opponent.trump):
                    opponent.trump = opponent.hand[c]

        if player.trump and opponent.trump:
            if deck.order(player.trump) < deck.order(opponent.trump):
                player.moving = True
            else:
                player.moving = False
        elif player.trump:
            player.moving = True
        elif opponent.trump:
            player.moving = False
        else:
            player.moving = random.randint(0, 1)

        deck.table = []

        game.first_state()

        if not player.moving:
            opponent.make_move()

        Clock.schedule_once(game.update, 2)
        return game

app = DurakApp()

if __name__ == "__main__":
    app.run()
<|endoftext|>


<commit_before># vim: tabstop=4 shiftwidth=4 softtabstop=4

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

import commands
import errno
import glob
import os
import select

from eventlet import greenpool
from eventlet import greenthread

from nova import exception
from nova import test
from nova import utils
from nova.utils import parse_mailmap, str_dict_replace

class ExceptionTestCase(test.TestCase):
    @staticmethod
    def _raise_exc(exc):
        raise exc()

    def test_exceptions_raise(self):
        for name in dir(exception):
            exc = getattr(exception, name)
            if isinstance(exc, type):
                self.assertRaises(exc, self._raise_exc, exc)

class ProjectTestCase(test.TestCase):
    def test_authors_up_to_date(self):
        topdir = os.path.normpath(os.path.dirname(__file__) + '/../../')
        missing = set()
        contributors = set()
        mailmap = parse_mailmap(os.path.join(topdir, '.mailmap'))
        authors_file = open(os.path.join(topdir,
                                         'Authors'), 'r').read().lower()

        if os.path.exists(os.path.join(topdir, '.git')):
            for email in commands.getoutput('git log --format=%ae').split():
                if not email:
                    continue
                if "jenkins" in email and "openstack.org" in email:
                    continue
                email = '<' + email.lower() + '>'
                contributors.add(str_dict_replace(email, mailmap))
        else:
            return

        for contributor in contributors:
            if contributor == 'nova-core':
                continue
            if not contributor in authors_file:
                missing.add(contributor)

        self.assertTrue(len(missing) == 0,
                        '%r not listed in Authors' % missing)

    def test_all_new_migrations_have_downgrade(self):
        # NOTE(sirp): These migrations are old enough so that a downgrade
        # isn't a hard requirement. Would be nice to have, in these cases,
        # though, too.
        EXEMPT = """
        002_bexar.py
        003_add_label_to_networks.py
        004_add_zone_tables.py
        005_add_instance_metadata.py
        006_add_provider_data_to_volumes.py
        007_add_ipv6_to_fixed_ips.py
        009_add_instance_migrations.py
        011_live_migration.py
        012_add_ipv6_flatmanager.py
        015_add_auto_assign_to_floating_ips.py
        020_add_snapshot_id_to_volumes.py
        026_add_agent_table.py
        027_add_provider_firewall_rules.py
        """

        exempt = [e.strip() for e in EXEMPT.splitlines() if e.strip()]

        topdir = os.path.normpath(os.path.dirname(__file__) + '/../../')
        py_glob = os.path.join(topdir, "nova", "db", "sqlalchemy",
                               "migrate_repo", "versions", "*.py")
        missing_downgrade = []
        for path in glob.iglob(py_glob):
            has_upgrade = False
            has_downgrade = False
            with open(path, "r") as f:
                for line in f:
                    if 'def upgrade(' in line:
                        has_upgrade = True
                    if 'def downgrade(' in line:
                        has_downgrade = True

                if has_upgrade and not has_downgrade:
                    fname = os.path.basename(path)
                    if fname not in exempt:
                        missing_downgrade.append(fname)

        helpful_msg = (_("The following migrations are missing a downgrade:"
                         "\n\t%s") % '\n\t'.join(sorted(missing_downgrade)))
        self.assert_(not missing_downgrade, helpful_msg)

class LockTestCase(test.TestCase):
    def test_synchronized_wrapped_function_metadata(self):
        @utils.synchronized('whatever')
        def foo():
            """Bar"""
            pass
        self.assertEquals(foo.__doc__, 'Bar', "Wrapped function's docstring "
                                              "got lost")
        self.assertEquals(foo.__name__, 'foo', "Wrapped function's name "
                                               "got mangled")

    def test_synchronized_internally(self):
        """We can lock across multiple green threads"""
        saved_sem_num = len(utils._semaphores)
        seen_threads = list()

        @utils.synchronized('testlock2', external=False)
        def f(id):
            for x in range(10):
                seen_threads.append(id)
                greenthread.sleep(0)

        threads = []
        pool = greenpool.GreenPool(10)
        for i in range(10):
            threads.append(pool.spawn(f, i))

        for thread in threads:
            thread.wait()

        self.assertEquals(len(seen_threads), 100)
        # Looking at the seen threads, split it into chunks of 10, and verify
        # that the last 9 match the first in each chunk.
        for i in range(10):
            for j in range(9):
                self.assertEquals(seen_threads[i * 10],
                                  seen_threads[i * 10 + 1 + j])

        self.assertEqual(saved_sem_num, len(utils._semaphores),
                         "Semaphore leak detected")

    def test_synchronized_externally(self):
        """We can lock across multiple processes"""
        rpipe1, wpipe1 = os.pipe()
        rpipe2, wpipe2 = os.pipe()

        @utils.synchronized('testlock1', external=True)
        def f(rpipe, wpipe):
            try:
                os.write(wpipe, "foo")
            except OSError, e:
                self.assertEquals(e.errno, errno.EPIPE)
                return

            rfds, _, __ = select.select([rpipe], [], [], 1)
            self.assertEquals(len(rfds), 0, "The other process, which was"
                                            " supposed to be locked, "
                                            "wrote on its end of the "
                                            "pipe")
            os.close(rpipe)

        pid = os.fork()
        if pid > 0:
            os.close(wpipe1)
            os.close(rpipe2)

            f(rpipe1, wpipe2)
        else:
            os.close(rpipe1)
            os.close(wpipe2)

            f(rpipe2, wpipe1)
            os._exit(0)
<commit_msg>Check all migrations have downgrade in test_misc<commit_after># vim: tabstop=4 shiftwidth=4 softtabstop=4

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

import commands
import errno
import glob
import os
import select

from eventlet import greenpool
from eventlet import greenthread

from nova import exception
from nova import test
from nova import utils
from nova.utils import parse_mailmap, str_dict_replace

class ExceptionTestCase(test.TestCase):
    @staticmethod
    def _raise_exc(exc):
        raise exc()

    def test_exceptions_raise(self):
        for name in dir(exception):
            exc = getattr(exception, name)
            if isinstance(exc, type):
                self.assertRaises(exc, self._raise_exc, exc)

class ProjectTestCase(test.TestCase):
    def test_authors_up_to_date(self):
        topdir = os.path.normpath(os.path.dirname(__file__) + '/../../')
        missing = set()
        contributors = set()
        mailmap = parse_mailmap(os.path.join(topdir, '.mailmap'))
        authors_file = open(os.path.join(topdir,
                                         'Authors'), 'r').read().lower()

        if os.path.exists(os.path.join(topdir, '.git')):
            for email in commands.getoutput('git log --format=%ae').split():
                if not email:
                    continue
                if "jenkins" in email and "openstack.org" in email:
                    continue
                email = '<' + email.lower() + '>'
                contributors.add(str_dict_replace(email, mailmap))
        else:
            return

        for contributor in contributors:
            if contributor == 'nova-core':
                continue
            if not contributor in authors_file:
                missing.add(contributor)

        self.assertTrue(len(missing) == 0,
                        '%r not listed in Authors' % missing)

    def test_all_migrations_have_downgrade(self):
        topdir = os.path.normpath(os.path.dirname(__file__) + '/../../')
        py_glob = os.path.join(topdir, "nova", "db", "sqlalchemy",
                               "migrate_repo", "versions", "*.py")
        missing_downgrade = []
        for path in glob.iglob(py_glob):
            has_upgrade = False
            has_downgrade = False
            with open(path, "r") as f:
                for line in f:
                    if 'def upgrade(' in line:
                        has_upgrade = True
                    if 'def downgrade(' in line:
                        has_downgrade = True

                if has_upgrade and not has_downgrade:
                    fname = os.path.basename(path)
                    missing_downgrade.append(fname)

        helpful_msg = (_("The following migrations are missing a downgrade:"
                         "\n\t%s") % '\n\t'.join(sorted(missing_downgrade)))
        self.assert_(not missing_downgrade, helpful_msg)

class LockTestCase(test.TestCase):
    def test_synchronized_wrapped_function_metadata(self):
        @utils.synchronized('whatever')
        def foo():
            """Bar"""
            pass
        self.assertEquals(foo.__doc__, 'Bar', "Wrapped function's docstring "
                                              "got lost")
        self.assertEquals(foo.__name__, 'foo', "Wrapped function's name "
                                               "got mangled")

    def test_synchronized_internally(self):
        """We can lock across multiple green threads"""
        saved_sem_num = len(utils._semaphores)
        seen_threads = list()

        @utils.synchronized('testlock2', external=False)
        def f(id):
            for x in range(10):
                seen_threads.append(id)
                greenthread.sleep(0)

        threads = []
        pool = greenpool.GreenPool(10)
        for i in range(10):
            threads.append(pool.spawn(f, i))

        for thread in threads:
            thread.wait()

        self.assertEquals(len(seen_threads), 100)
        # Looking at the seen threads, split it into chunks of 10, and verify
        # that the last 9 match the first in each chunk.
        for i in range(10):
            for j in range(9):
                self.assertEquals(seen_threads[i * 10],
                                  seen_threads[i * 10 + 1 + j])

        self.assertEqual(saved_sem_num, len(utils._semaphores),
                         "Semaphore leak detected")

    def test_synchronized_externally(self):
        """We can lock across multiple processes"""
        rpipe1, wpipe1 = os.pipe()
        rpipe2, wpipe2 = os.pipe()

        @utils.synchronized('testlock1', external=True)
        def f(rpipe, wpipe):
            try:
                os.write(wpipe, "foo")
            except OSError, e:
                self.assertEquals(e.errno, errno.EPIPE)
                return

            rfds, _, __ = select.select([rpipe], [], [], 1)
            self.assertEquals(len(rfds), 0, "The other process, which was"
                                            " supposed to be locked, "
                                            "wrote on its end of the "
                                            "pipe")
            os.close(rpipe)

        pid = os.fork()
        if pid > 0:
            os.close(wpipe1)
            os.close(rpipe2)

            f(rpipe1, wpipe2)
        else:
            os.close(rpipe1)
            os.close(wpipe2)

            f(rpipe2, wpipe1)
            os._exit(0)
<|endoftext|>