<commit_before>#!/usr/bin/env python
#     Copyright 2019, Kay Hayen, mailto:kay.hayen@gmail.com
#
#     Part of "Nuitka", an optimizing Python compiler that is compatible and
#     integrates with CPython, but also works on its own.
#
#     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.
#

""" Main program for autoformat tool.

"""

import glob
import sys
from optparse import OptionParser

from nuitka.tools.Basics import goHome
from nuitka.tools.quality.Git import getStagedFileChangeDesc
from nuitka.tools.quality.ScanSources import scanTargets
from nuitka.Tracing import my_print

from .Autoformat import autoformat

def resolveShellPatternToFilenames(pattern):
    return glob.glob(pattern)

def main():
    parser = OptionParser()

    parser.add_option(
        "--verbose",
        action="store_true",
        dest="verbose",
        default=False,
        help="""Default is %default.""",
    )

    parser.add_option(
        "--from-commit",
        action="store_true",
        dest="from_commit",
        default=False,
        help="""From commit hook, do not descend into directories. Default is %default.""",
    )

    parser.add_option(
        "--abort-on-parsing-error",
        action="store_true",
        dest="abort",
        default=False,
        help="""Stop if an error occurs, or continue. Default is %default.""",
    )

    options, positional_args = parser.parse_args()

    if options.from_commit:
        assert not positional_args
        for desc in getStagedFileChangeDesc():
            autoformat(desc["src_path"], git_stage=desc, abort=options.abort)
    else:
        if not positional_args:
            positional_args = ["bin", "nuitka", "tests/*/run_all.py"]

        my_print("Working on:", positional_args)

        positional_args = sum(
            (
                resolveShellPatternToFilenames(positional_arg)
                for positional_arg in positional_args
            ),
            [],
        )

        goHome()

        filenames = list(
            scanTargets(positional_args, (".py", ".scons", ".rst", ".txt", ".j2"))
        )
        if not filenames:
            sys.exit("No files found.")

        for filename in filenames:
            autoformat(filename, git_stage=False, abort=options.abort)

if __name__ == "__main__":
    main()
<commit_msg>Quality: Also autoformat markdown files.<commit_after>#!/usr/bin/env python
#     Copyright 2019, Kay Hayen, mailto:kay.hayen@gmail.com
#
#     Part of "Nuitka", an optimizing Python compiler that is compatible and
#     integrates with CPython, but also works on its own.
#
#     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.
#

""" Main program for autoformat tool.

"""

import glob
import sys
from optparse import OptionParser

from nuitka.tools.Basics import goHome
from nuitka.tools.quality.Git import getStagedFileChangeDesc
from nuitka.tools.quality.ScanSources import scanTargets
from nuitka.Tracing import my_print

from .Autoformat import autoformat

def resolveShellPatternToFilenames(pattern):
    return glob.glob(pattern)

def main():
    parser = OptionParser()

    parser.add_option(
        "--verbose",
        action="store_true",
        dest="verbose",
        default=False,
        help="""Default is %default.""",
    )

    parser.add_option(
        "--from-commit",
        action="store_true",
        dest="from_commit",
        default=False,
        help="""From commit hook, do not descend into directories. Default is %default.""",
    )

    parser.add_option(
        "--abort-on-parsing-error",
        action="store_true",
        dest="abort",
        default=False,
        help="""Stop if an error occurs, or continue. Default is %default.""",
    )

    options, positional_args = parser.parse_args()

    if options.from_commit:
        assert not positional_args
        for desc in getStagedFileChangeDesc():
            autoformat(desc["src_path"], git_stage=desc, abort=options.abort)
    else:
        if not positional_args:
            positional_args = ["bin", "nuitka", "tests/*/run_all.py"]

        my_print("Working on:", positional_args)

        positional_args = sum(
            (
                resolveShellPatternToFilenames(positional_arg)
                for positional_arg in positional_args
            ),
            [],
        )

        goHome()

        filenames = list(
            scanTargets(
                positional_args, (".py", ".scons", ".rst", ".txt", ".j2", "*.md")
            )
        )
        if not filenames:
            sys.exit("No files found.")

        for filename in filenames:
            autoformat(filename, git_stage=False, abort=options.abort)

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


<commit_before>from __future__ import print_function
import numpy as np
from astropy.wcs import WCS
import warnings
from astropy import units as u
from astropy import log

wcs_parameters_to_preserve = ['cel_offset', 'dateavg', 'dateobs', 'equinox',
                              'latpole', 'lonpole', 'mjdavg', 'mjdobs', 'name',
                              'obsgeo', 'phi0', 'radesys', 'restfrq',
                              'restwav', 'specsys', 'ssysobs', 'ssyssrc',
                              'theta0', 'velangl', 'velosys', 'zsource']
# not writable:
# 'lat', 'lng', 'lattyp', 'lngtyp',

bad_spectypes_mapping = {'VELOCITY':'VELO',
                         'WAVELENG':'WAVE',
                         }

def drop_axis(wcs, dropax):
    """
    Drop the ax on axis dropax

    Remove an axis from the WCS
    Parameters
    ----------
    wcs: astropy.wcs.WCS
        The WCS with naxis to be chopped to naxis-1
    dropax: int
        The index of the WCS to drop, counting from 0 (i.e., python convention,
        not FITS convention)
    """
    inds = list(range(wcs.wcs.naxis))
    inds.pop(dropax)
    inds = np.array(inds)

    return reindex_wcs(wcs, inds)

def add_stokes_axis_to_wcs(wcs, add_before_ind):
    """
    Add a new Stokes axis that is uncorrelated with any other axes

    Parameters
    ----------
    wcs: astropy.wcs.WCS
        The WCS to add to
    add_before_ind: int
        Index of the WCS to insert the new Stokes axis in front of.
        To add at the end, do add_before_ind = wcs.wcs.naxis
    """

    naxin = wcs.wcs.naxis
    naxout = naxin + 1

    inds = list(range(naxout))
    inds.pop(add_before_ind)
    inds = np.array(inds)

    outwcs = WCS(naxis=naxout)
    for par in wcs_parameters_to_preserve:
        setattr(outwcs.wcs, par, getattr(wcs.wcs, par))

    pc = np.zeros([naxout, naxout])
    pc[inds[:, np.newaxis], inds[np.newaxis, :]] = wcs.wcs.get_pc()
    pc[add_before_ind, add_before_ind] = 1

    def append_to_end(val, lst):
        """ insert a value at index into a list """
        return list(lst) + [val]

    outwcs.wcs.crpix = append_to_end(1, wcs.wcs.crpix)
    outwcs.wcs.cdelt = append_to_end(1, wcs.wcs.get_cdelt())
    outwcs.wcs.crval = append_to_end(1, wcs.wcs.crval)
    outwcs.wcs.cunit = append_to_end("", wcs.wcs.cunit)
    outwcs.wcs.ctype = append_to_end("STOKES", wcs.wcs.ctype)
    outwcs.wcs.cname = append_to_end("STOKES", wcs.wcs.cname)
    outwcs.wcs.pc = pc

    return outwcs

def wcs_swapaxes(wcs, ax0, ax1):
    """
    Swap axes in a WCS

    Parameters
    ----------
    wcs: astropy.wcs.WCS
        The WCS to have its axes swapped
    ax0: int
    ax1: int
        The indices of the WCS to be swapped, counting from 0 (i.e., python
        convention, not FITS convention)
    """
    inds = list(range(wcs.wcs.naxis))
    inds[ax0], inds[ax1] = inds[ax1], inds[ax0]
    inds = np.array(inds)

    return reindex_wcs(wcs, inds)

def reindex_wcs(wcs, inds):
    """
    Re-index a WCS given indices.  The number of axes may be reduced.

    Parameters
    ----------
    wcs: astropy.wcs.WCS
        The WCS to be manipulated
    inds: np.array(dtype='int')
        The indices of the array to keep in the output.
        e.g. swapaxes: [0,2,1,3]
        dropaxes: [0,1,3]
    """

    if not isinstance(inds, np.ndarray):
        raise TypeError("Indices must be an ndarray")

    if inds.dtype.kind != 'i':
        raise TypeError('Indices must be integers')

    outwcs = WCS(naxis=len(inds))
    for par in wcs_parameters_to_preserve:
        setattr(outwcs.wcs, par, getattr(wcs.wcs, par))

    cdelt = wcs.wcs.get_cdelt()
    pc = wcs.wcs.get_pc()

    outwcs.wcs.crpix = wcs.wcs.crpix[inds]
    outwcs.wcs.cdelt = cdelt[inds]
    outwcs.wcs.crval = wcs.wcs.crval[inds]
    outwcs.wcs.cunit = [wcs.wcs.cunit[i] for i in inds]
    outwcs.wcs.ctype = [wcs.wcs.ctype[i] for i in inds]
    outwcs.wcs.cname = [wcs.wcs.cname[i] for i in inds]
    outwcs.wcs.pc = pc[inds[:, None], inds[None, :]]

    return outwcs

def axis_names(wcs):
    """
    Extract world names for each coordinate axis

    Parameters
    ----------
    wcs : astropy.wcs.WCS
        The WCS object to extract names from

    Returns
    -------
    A tuple of names along each axis
    """
    names = list(wcs.wcs.cname)
    types = wcs.wcs.ctype
    for i in range(len(names)):
        if len(names[i]) > 0:
            continue
        names[i] = types[i].split('-')[0]
    return names

def slice_wcs(wcs, view):
    """
    Slice a WCS instance using a Numpy slice. The order of the slice should
    be reversed (as for the data) compared to the natural WCS order.

    Parameters
    ----------
    view : tuple
        A tuple containing the same number of slices as the WCS system

    Returns
    -------
    A new `~astropy.wcs.WCS` instance
    """
    if len(view) != wcs.wcs.naxis:
        raise ValueError("Must have same number of slices as number of WCS axes")

    wcs_new = wcs.deepcopy()

    # Indexing the WCS: x,y,z order (not numpy z,y,x order)
    intslices = [wcs.wcs.naxis-ii-1 for ii,s in enumerate(view) if not hasattr(s,'start')]

    for ii in intslices:
        wcs_new = wcs_new.dropaxis(ii)
    view = [s for s in view if hasattr(s,'start')]

    for i, iview in enumerate(view):
        if iview.start is not None:
            if iview.step not in (None, 1):
                raise NotImplementedError("Cannot yet slice WCS with strides different from None or 1")
            wcs_index = wcs.wcs.naxis - 1 - i
            wcs_new.wcs.crpix[wcs_index] -= iview.start
    return wcs_new

def check_equality(wcs1, wcs2, warn_missing=False, ignore_keywords=['MJD-OBS',
                                                                    'VELOSYS']):
    """
    Check if two WCSs are equal

    Parameters
    ----------
    wcs1, wcs2: `astropy.wcs.WCS`
        The WCSs
    warn_missing: bool
        Issue warnings if one header is missing a keyword that the other has?
    ignore_keywords: list of str
        Keywords that are stored as part of the WCS but do not define part of
        the coordinate system and therefore can be safely ignored.
    """

    # naive version:
    # return str(wcs1.to_header()) != str(wcs2.to_header())

    h1 = wcs1.to_header()
    h2 = wcs2.to_header()

    # Default to headers equal; everything below changes to false if there are
    # any inequalities
    OK = True
    # to keep track of keywords in both
    matched = []

    for c1 in h1.cards:
        key = c1[0]
        if key in h2:
            matched.append(key)
            c2 = h2.cards[key]
            # special check for units: "m/s" = "m s-1"
            if 'UNIT' in key:
                u1 = u.Unit(c1[1])
                u2 = u.Unit(c2[1])
                if u1 != u2:
                    if key in ignore_keywords:
                        log.debug("IGNORED Header 1, {0}: {1} != {2}".format(key,u1,u2))
                    else:
                        OK = False
                        log.debug("Header 1, {0}: {1} != {2}".format(key,u1,u2))
            elif isinstance(c1[1], (float, np.float)):
                try:
                    np.testing.assert_almost_equal(c1[1], c2[1])
                except AssertionError:
                    if key in ('RESTFRQ','RESTWAV'):
                        warnings.warn("{0} is not equal in WCS; ignoring ".format(key)+
                                      "under the assumption that you want to"
                                      " compare velocity cubes.")
                        continue
                    if key in ignore_keywords:
                        log.debug("IGNORED Header 1, {0}: {1} != {2}".format(key,c1[1],c2[1]))
                    else:
                        log.debug("Header 1, {0}: {1} != {2}".format(key,c1[1],c2[1]))
                        OK = False
            elif c1[1] != c2[1]:
                if key in ignore_keywords:
                    log.debug("IGNORED Header 1, {0}: {1} != {2}".format(key,c1[1],c2[1]))
                else:
                    log.debug("Header 1, {0}: {1} != {2}".format(key,c1[1],c2[1]))
                    OK = False
        else:
            if warn_missing:
                warnings.warn("WCS2 is missing card {0}".format(key))
            elif key not in ignore_keywords:
                OK = False

    # Check that there aren't any cards in header 2 that were missing from
    # header 1
    for c2 in h2.cards:
        key = c2[0]
        if key not in matched:
            if warn_missing:
                warnings.warn("WCS1 is missing card {0}".format(key))
            else:
                OK = False

    return OK
<commit_msg>update WCS slicing to fix bug noted in astropy #2909<commit_after>from __future__ import print_function
import numpy as np
from astropy.wcs import WCS
import warnings
from astropy import units as u
from astropy import log

wcs_parameters_to_preserve = ['cel_offset', 'dateavg', 'dateobs', 'equinox',
                              'latpole', 'lonpole', 'mjdavg', 'mjdobs', 'name',
                              'obsgeo', 'phi0', 'radesys', 'restfrq',
                              'restwav', 'specsys', 'ssysobs', 'ssyssrc',
                              'theta0', 'velangl', 'velosys', 'zsource']
# not writable:
# 'lat', 'lng', 'lattyp', 'lngtyp',

bad_spectypes_mapping = {'VELOCITY':'VELO',
                         'WAVELENG':'WAVE',
                         }

def drop_axis(wcs, dropax):
    """
    Drop the ax on axis dropax

    Remove an axis from the WCS
    Parameters
    ----------
    wcs: astropy.wcs.WCS
        The WCS with naxis to be chopped to naxis-1
    dropax: int
        The index of the WCS to drop, counting from 0 (i.e., python convention,
        not FITS convention)
    """
    inds = list(range(wcs.wcs.naxis))
    inds.pop(dropax)
    inds = np.array(inds)

    return reindex_wcs(wcs, inds)

def add_stokes_axis_to_wcs(wcs, add_before_ind):
    """
    Add a new Stokes axis that is uncorrelated with any other axes

    Parameters
    ----------
    wcs: astropy.wcs.WCS
        The WCS to add to
    add_before_ind: int
        Index of the WCS to insert the new Stokes axis in front of.
        To add at the end, do add_before_ind = wcs.wcs.naxis
    """

    naxin = wcs.wcs.naxis
    naxout = naxin + 1

    inds = list(range(naxout))
    inds.pop(add_before_ind)
    inds = np.array(inds)

    outwcs = WCS(naxis=naxout)
    for par in wcs_parameters_to_preserve:
        setattr(outwcs.wcs, par, getattr(wcs.wcs, par))

    pc = np.zeros([naxout, naxout])
    pc[inds[:, np.newaxis], inds[np.newaxis, :]] = wcs.wcs.get_pc()
    pc[add_before_ind, add_before_ind] = 1

    def append_to_end(val, lst):
        """ insert a value at index into a list """
        return list(lst) + [val]

    outwcs.wcs.crpix = append_to_end(1, wcs.wcs.crpix)
    outwcs.wcs.cdelt = append_to_end(1, wcs.wcs.get_cdelt())
    outwcs.wcs.crval = append_to_end(1, wcs.wcs.crval)
    outwcs.wcs.cunit = append_to_end("", wcs.wcs.cunit)
    outwcs.wcs.ctype = append_to_end("STOKES", wcs.wcs.ctype)
    outwcs.wcs.cname = append_to_end("STOKES", wcs.wcs.cname)
    outwcs.wcs.pc = pc

    return outwcs

def wcs_swapaxes(wcs, ax0, ax1):
    """
    Swap axes in a WCS

    Parameters
    ----------
    wcs: astropy.wcs.WCS
        The WCS to have its axes swapped
    ax0: int
    ax1: int
        The indices of the WCS to be swapped, counting from 0 (i.e., python
        convention, not FITS convention)
    """
    inds = list(range(wcs.wcs.naxis))
    inds[ax0], inds[ax1] = inds[ax1], inds[ax0]
    inds = np.array(inds)

    return reindex_wcs(wcs, inds)

def reindex_wcs(wcs, inds):
    """
    Re-index a WCS given indices.  The number of axes may be reduced.

    Parameters
    ----------
    wcs: astropy.wcs.WCS
        The WCS to be manipulated
    inds: np.array(dtype='int')
        The indices of the array to keep in the output.
        e.g. swapaxes: [0,2,1,3]
        dropaxes: [0,1,3]
    """

    if not isinstance(inds, np.ndarray):
        raise TypeError("Indices must be an ndarray")

    if inds.dtype.kind != 'i':
        raise TypeError('Indices must be integers')

    outwcs = WCS(naxis=len(inds))
    for par in wcs_parameters_to_preserve:
        setattr(outwcs.wcs, par, getattr(wcs.wcs, par))

    cdelt = wcs.wcs.get_cdelt()
    pc = wcs.wcs.get_pc()

    outwcs.wcs.crpix = wcs.wcs.crpix[inds]
    outwcs.wcs.cdelt = cdelt[inds]
    outwcs.wcs.crval = wcs.wcs.crval[inds]
    outwcs.wcs.cunit = [wcs.wcs.cunit[i] for i in inds]
    outwcs.wcs.ctype = [wcs.wcs.ctype[i] for i in inds]
    outwcs.wcs.cname = [wcs.wcs.cname[i] for i in inds]
    outwcs.wcs.pc = pc[inds[:, None], inds[None, :]]

    return outwcs

def axis_names(wcs):
    """
    Extract world names for each coordinate axis

    Parameters
    ----------
    wcs : astropy.wcs.WCS
        The WCS object to extract names from

    Returns
    -------
    A tuple of names along each axis
    """
    names = list(wcs.wcs.cname)
    types = wcs.wcs.ctype
    for i in range(len(names)):
        if len(names[i]) > 0:
            continue
        names[i] = types[i].split('-')[0]
    return names

def slice(mywcs, view, numpy_order=True):
    """
    Slice a WCS instance using a Numpy slice. The order of the slice should
    be reversed (as for the data) compared to the natural WCS order.

    Parameters
    ----------
    view : tuple
        A tuple containing the same number of slices as the WCS system.
        The ``step`` method, the third argument to a slice, is not
        presently supported.
    numpy_order : bool
        Use numpy order, i.e. slice the WCS so that an identical slice
        applied to a numpy array will slice the array and WCS in the same
        way. If set to `False`, the WCS will be sliced in FITS order,
        meaning the first slice will be applied to the *last* numpy index
        but the *first* WCS axis.

    Returns
    -------
    wcs_new : `~astropy.wcs.WCS`
        A new resampled WCS axis
    """
    if hasattr(view, '__len__') and len(view) > mywcs.wcs.naxis:
        raise ValueError("Must have # of slices <= # of WCS axes")
    elif not hasattr(view, '__len__'): # view MUST be an iterable
        view = [view]

    if not all([isinstance(x, slice) for x in view]):
        raise ValueError("Cannot downsample a WCS with indexing.  Use "
                         "wcs.sub or wcs.dropaxis if you want to remove "
                         "axes.")

    wcs_new = mywcs.deepcopy()
    for i, iview in enumerate(view):
        if iview.step is not None and iview.start is None:
            # Slice from "None" is equivalent to slice from 0 (but one
            # might want to downsample, so allow slices with
            # None,None,step or None,stop,step)
            iview = slice(0, iview.stop, iview.step)

        if iview.start is not None:
            if numpy_order:
                wcs_index = mywcs.wcs.naxis - 1 - i
            else:
                wcs_index = i

            if iview.step not in (None, 1):
                crpix = mywcs.wcs.crpix[wcs_index]
                cdelt = mywcs.wcs.cdelt[wcs_index]
                # equivalently (keep this comment so you can compare eqns):
                # wcs_new.wcs.crpix[wcs_index] =
                # (crpix - iview.start)*iview.step + 0.5 - iview.step/2.
                crp = ((crpix - iview.start - 1.)/iview.step
                       + 0.5 + 1./iview.step/2.)
                wcs_new.wcs.crpix[wcs_index] = crp
                wcs_new.wcs.cdelt[wcs_index] = cdelt * iview.step
            else:
                wcs_new.wcs.crpix[wcs_index] -= iview.start
    return wcs_new

def check_equality(wcs1, wcs2, warn_missing=False, ignore_keywords=['MJD-OBS',
                                                                    'VELOSYS']):
    """
    Check if two WCSs are equal

    Parameters
    ----------
    wcs1, wcs2: `astropy.wcs.WCS`
        The WCSs
    warn_missing: bool
        Issue warnings if one header is missing a keyword that the other has?
    ignore_keywords: list of str
        Keywords that are stored as part of the WCS but do not define part of
        the coordinate system and therefore can be safely ignored.
    """

    # naive version:
    # return str(wcs1.to_header()) != str(wcs2.to_header())

    h1 = wcs1.to_header()
    h2 = wcs2.to_header()

    # Default to headers equal; everything below changes to false if there are
    # any inequalities
    OK = True
    # to keep track of keywords in both
    matched = []

    for c1 in h1.cards:
        key = c1[0]
        if key in h2:
            matched.append(key)
            c2 = h2.cards[key]
            # special check for units: "m/s" = "m s-1"
            if 'UNIT' in key:
                u1 = u.Unit(c1[1])
                u2 = u.Unit(c2[1])
                if u1 != u2:
                    if key in ignore_keywords:
                        log.debug("IGNORED Header 1, {0}: {1} != {2}".format(key,u1,u2))
                    else:
                        OK = False
                        log.debug("Header 1, {0}: {1} != {2}".format(key,u1,u2))
            elif isinstance(c1[1], (float, np.float)):
                try:
                    np.testing.assert_almost_equal(c1[1], c2[1])
                except AssertionError:
                    if key in ('RESTFRQ','RESTWAV'):
                        warnings.warn("{0} is not equal in WCS; ignoring ".format(key)+
                                      "under the assumption that you want to"
                                      " compare velocity cubes.")
                        continue
                    if key in ignore_keywords:
                        log.debug("IGNORED Header 1, {0}: {1} != {2}".format(key,c1[1],c2[1]))
                    else:
                        log.debug("Header 1, {0}: {1} != {2}".format(key,c1[1],c2[1]))
                        OK = False
            elif c1[1] != c2[1]:
                if key in ignore_keywords:
                    log.debug("IGNORED Header 1, {0}: {1} != {2}".format(key,c1[1],c2[1]))
                else:
                    log.debug("Header 1, {0}: {1} != {2}".format(key,c1[1],c2[1]))
                    OK = False
        else:
            if warn_missing:
                warnings.warn("WCS2 is missing card {0}".format(key))
            elif key not in ignore_keywords:
                OK = False

    # Check that there aren't any cards in header 2 that were missing from
    # header 1
    for c2 in h2.cards:
        key = c2[0]
        if key not in matched:
            if warn_missing:
                warnings.warn("WCS1 is missing card {0}".format(key))
            else:
                OK = False

    return OK
<|endoftext|>


<commit_before>###############################################################################
##
##  Copyright 2011-2013 Tavendo GmbH
##
##  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 jinja2
import os
import sys

__all__ = ("CSS_COMMON",
           "CSS_MASTER_REPORT",
           "CSS_DETAIL_REPORT",
           "JS_MASTER_REPORT",
           "HtmlReport")

## TODO: Move the constants to jinja2 template files

##
## CSS/JS include bits for WebSocket and WAMP test reports
##

## CSS common for all reports
##
CSS_COMMON = """
body {
   background-color: #F4F4F4;
   color: #333;
   font-family: Segoe UI,Tahoma,Arial,Verdana,sans-serif;
}

p#intro {
   font-family: Cambria,serif;
   font-size: 1.1em;
   color: #444;
}

p#intro a {
   color: #444;
}

p#intro a:visited {
   color: #444;
}

.block {
   background-color: #e0e0e0;
   padding: 16px;
   margin: 20px;
}

p.case_text_block {
   border-radius: 10px;
   border: 1px solid #aaa;
   padding: 16px;
   margin: 4px 20px;
   color: #444;
}

p.case_desc {
}

p.case_expect {
}

p.case_outcome {
}

p.case_closing_beh {
}

pre.http_dump {
   font-family: Consolas, "Courier New", monospace;
   font-size: 0.8em;
   color: #333;
   border-radius: 10px;
   border: 1px solid #aaa;
   padding: 16px;
   margin: 4px 20px;
}

span.case_pickle {
   font-family: Consolas, "Courier New", monospace;
   font-size: 0.7em;
   color: #000;
}

p#case_result,p#close_result {
   border-radius: 10px;
   background-color: #e8e2d1;
   padding: 20px;
   margin: 20px;
}

h1 {
   margin-left: 60px;
}

h2 {
   margin-left: 30px;
}

h3 {
   margin-left: 50px;
}

a.up {
   float: right;
   border-radius: 16px;
   margin-top: 16px;
   margin-bottom: 10px;

   margin-right: 30px;
   padding-left: 10px;
   padding-right: 10px;
   padding-bottom: 2px;
   padding-top: 2px;
   background-color: #666;
   color: #fff;
   text-decoration: none;
   font-size: 0.8em;
}

a.up:visited {
}

a.up:hover {
   background-color: #028ec9;
}
"""

## CSS for Master report
##
CSS_MASTER_REPORT = """
table {
   border-collapse: collapse;
   border-spacing: 0px;
}

td {
   margin: 0;
   border: 1px solid #fff;
   padding-top: 6px;
   padding-bottom: 6px;
   padding-left: 16px;
   padding-right: 16px;
   font-size: 0.9em;
   color: #fff;
}

table#agent_case_results {
   border-collapse: collapse;
   border-spacing: 0px;
   border-radius: 10px;
   margin-left: 20px;
   margin-right: 20px;
   margin-bottom: 40px;
}

td.outcome_desc {
   width: 100%;
   color: #333;
   font-size: 0.8em;
}

tr.agent_case_result_row a {
   color: #eee;
}

td.agent {
   color: #fff;
   font-size: 1.0em;
   text-align: center;
   background-color: #048;
   font-size: 0.8em;
   word-wrap: break-word;
   padding: 4px;
   width: 140px;
}

td.case {
   background-color: #666;
   text-align: left;
   padding-left: 40px;
   font-size: 0.9em;
}

td.case_category {
   color: #fff;
   background-color: #000;
   text-align: left;
   padding-left: 20px;
   font-size: 1.0em;
}

td.case_subcategory {
   color: #fff;
   background-color: #333;
   text-align: left;
   padding-left: 30px;
   font-size: 0.9em;
}

td.close {
   width: 15px;
   padding: 6px;
   font-size: 0.7em;
   color: #fff;
   min-width: 0px;
}

td.case_ok {
   background-color: #0a0;
   text-align: center;
}

td.case_almost {
   background-color: #6d6;
   text-align: center;
}

td.case_non_strict, td.case_no_close {
   background-color: #9a0;
   text-align: center;
}

td.case_info {
   background-color: #4095BF;
   text-align: center;
}

td.case_unimplemented {
   background-color: #800080;
   text-align: center;
}

td.case_failed {
   background-color: #900;
   text-align: center;
}

td.case_missing {
   color: #fff;
   background-color: #a05a2c;
   text-align: center;
}

span.case_duration {
   font-size: 0.7em;
   color: #fff;
}

*.unselectable {
   user-select: none;
   -moz-user-select: -moz-none;
   -webkit-user-select: none;
   -khtml-user-select: none;
}

div#toggle_button {
   position: fixed;
   bottom: 10px;
   right: 10px;
   background-color: rgba(60, 60, 60, 0.5);
   border-radius: 12px;
   color: #fff;
   font-size: 0.7em;
   padding: 5px 10px;
}

div#toggle_button:hover {
   background-color: #028ec9;
}
"""

## CSS for Agent/Case detail report
##
CSS_DETAIL_REPORT = """
p.case {
   color: #fff;
   border-radius: 10px;
   padding: 20px;
   margin: 12px 20px;
   font-size: 1.2em;
}

p.case_ok {
   background-color: #0a0;
}

p.case_non_strict, p.case_no_close {
   background-color: #9a0;
}

p.case_info {
   background-color: #4095BF;
}

p.case_failed {
   background-color: #900;
}

table {
   border-collapse: collapse;
   border-spacing: 0px;
   margin-left: 80px;
   margin-bottom: 12px;
   margin-top: 0px;
}

td
{
   margin: 0;
   font-size: 0.8em;
   border: 1px #fff solid;
   padding-top: 6px;
   padding-bottom: 6px;
   padding-left: 16px;
   padding-right: 16px;
   text-align: right;
}

td.right {
   text-align: right;
}

td.left {
   text-align: left;
}

tr.stats_header {
   color: #eee;
   background-color: #000;
}

tr.stats_row {
   color: #000;
   background-color: #fc3;
}

tr.stats_total {
   color: #fff;
   background-color: #888;
}

div#wirelog {
   margin-top: 20px;
   margin-bottom: 80px;
}

pre.wirelog_rx_octets {color: #aaa; margin: 0; background-color: #060; padding: 2px;}
pre.wirelog_tx_octets {color: #aaa; margin: 0; background-color: #600; padding: 2px;}
pre.wirelog_tx_octets_sync {color: #aaa; margin: 0; background-color: #606; padding: 2px;}

pre.wirelog_rx_frame {color: #fff; margin: 0; background-color: #0a0; padding: 2px;}
pre.wirelog_tx_frame {color: #fff; margin: 0; background-color: #a00; padding: 2px;}
pre.wirelog_tx_frame_sync {color: #fff; margin: 0; background-color: #a0a; padding: 2px;}

pre.wirelog_delay {color: #fff; margin: 0; background-color: #000; padding: 2px;}
pre.wirelog_kill_after {color: #fff; margin: 0; background-color: #000; padding: 2px;}

pre.wirelog_tcp_closed_by_me {color: #fff; margin: 0; background-color: #008; padding: 2px;}
pre.wirelog_tcp_closed_by_peer {color: #fff; margin: 0; background-color: #000; padding: 2px;}
"""

## JavaScript for master report
##
## Template vars:
##    agents_cnt => int => len(self.agents.keys())
##
JS_MASTER_REPORT = """
var isClosed = false;

function closeHelper(display,colspan) {
   // hide all close codes
   var a = document.getElementsByClassName("close_hide");
   for (var i in a) {
      if (a[i].style) {
         a[i].style.display = display;
      }
   }

   // set colspans
   var a = document.getElementsByClassName("close_flex");
   for (var i in a) {
      a[i].colSpan = colspan;
   }

   var a = document.getElementsByClassName("case_subcategory");
   for (var i in a) {
      a[i].colSpan = %(agents_cnt)d * colspan + 1;
   }
}

function toggleClose() {
   if (window.isClosed == false) {
      closeHelper("none",1);
      window.isClosed = true;
   } else {
      closeHelper("table-cell",2);
      window.isClosed = false;
   }
}
"""

REPORT_DIR_PERMISSIONS = 0770

from zope.interface import implementer
from interfaces import IReportGenerator

@implementer(IReportGenerator)
class HtmlReportGenerator(object):

    def __init__(self, test_db, report_dirname):
        self.test_db = test_db
        self.report_dirname = report_dirname
        env = jinja2.Environment(
            loader=jinja2.PackageLoader("autobahntestsuite", "templates"),
            line_statement_prefix="#",
            line_comment_prefix="##")
        self.wamp_details_tpl = env.get_template("wamp_details.html")
        self.wamp_index_tpl = env.get_template("wamp_overview.html")

        # Check if the 'reports' directory exists; try to create it otherwise.
        if not os.path.isdir(report_dirname):
            self.createReportDirectory()

    def writeReportIndexFile(self, runId, file = None):
       # return a Deferred that yields the automatically
       # chose filename if no file-like objct was provided,
       # and None otherwise
       raise Exception("implement me")

    def writeReportFile(self, resultId, file = None):
       # return a Deferred that yields the automatically
       # chose filename if no file-like objct was provided,
       # and None otherwise
       raise Exception("implement me")

    def createReportDirectory(self):
       """
       Create the directory for storing the reports. If this is not possible,
       terminate the script.
       """
       try:
          os.makedirs(self.report_dirname, REPORT_DIR_PERMISSIONS)
       except OSError, exc:
          print "Could not create directory: %s" % exc
          sys.exit(1)

    ### TODO: Move the creation of reports to a separate class.
    def createReport(self, res, report_filename, readable_test_name, agent,
                     description):
       """
       Create an HTML file called `report_filename` in the
       `report_dirname` directory with details about the test case.
       """
       report_path = os.path.join(self.report_dirname, report_filename)
       try:
          f = open(report_path, "w")
       except IOError, ex:
          print "Could not create file %s: %s." % (report_path, ex)
          return
       try:
           f.write(self.formatResultAsHtml(res, readable_test_name, agent,
                                           description))
       except Exception, ex:
           print "Could not write report: %s." % ex
       f.close()

    def formatResultAsHtml(self, res, readable_test_name, agent, description):
       """
       Create an HTML document with a table containing information about
       the test outcome.
       """
       html = self.wamp_details_tpl.render(record_list=res[3],
                                           test_name = readable_test_name,
                                           expected=res[1],
                                           observed=res[2],
                                           outcome="Pass" if res[0] else "Fail",
                                           agent=agent,
                                           description=description)
       return html

    def createIndex(self, reports):
        """
        Create an HTML document with a table containing an overview of all
        tests and links to the detailed documents.
        """
        try:
            with open(os.path.join(self.report_dirname, "index.html"),
                      "w") as f:
                html = self.wamp_index_tpl.render(categories=reports)
                f.write(html)
        except Exception, ex:
            print "Could not create index file: %s" % ex
<commit_msg>Spelling: choose<commit_after>###############################################################################
##
##  Copyright 2011-2013 Tavendo GmbH
##
##  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 jinja2
import os
import sys

__all__ = ("CSS_COMMON",
           "CSS_MASTER_REPORT",
           "CSS_DETAIL_REPORT",
           "JS_MASTER_REPORT",
           "HtmlReport")

## TODO: Move the constants to jinja2 template files

##
## CSS/JS include bits for WebSocket and WAMP test reports
##

## CSS common for all reports
##
CSS_COMMON = """
body {
   background-color: #F4F4F4;
   color: #333;
   font-family: Segoe UI,Tahoma,Arial,Verdana,sans-serif;
}

p#intro {
   font-family: Cambria,serif;
   font-size: 1.1em;
   color: #444;
}

p#intro a {
   color: #444;
}

p#intro a:visited {
   color: #444;
}

.block {
   background-color: #e0e0e0;
   padding: 16px;
   margin: 20px;
}

p.case_text_block {
   border-radius: 10px;
   border: 1px solid #aaa;
   padding: 16px;
   margin: 4px 20px;
   color: #444;
}

p.case_desc {
}

p.case_expect {
}

p.case_outcome {
}

p.case_closing_beh {
}

pre.http_dump {
   font-family: Consolas, "Courier New", monospace;
   font-size: 0.8em;
   color: #333;
   border-radius: 10px;
   border: 1px solid #aaa;
   padding: 16px;
   margin: 4px 20px;
}

span.case_pickle {
   font-family: Consolas, "Courier New", monospace;
   font-size: 0.7em;
   color: #000;
}

p#case_result,p#close_result {
   border-radius: 10px;
   background-color: #e8e2d1;
   padding: 20px;
   margin: 20px;
}

h1 {
   margin-left: 60px;
}

h2 {
   margin-left: 30px;
}

h3 {
   margin-left: 50px;
}

a.up {
   float: right;
   border-radius: 16px;
   margin-top: 16px;
   margin-bottom: 10px;

   margin-right: 30px;
   padding-left: 10px;
   padding-right: 10px;
   padding-bottom: 2px;
   padding-top: 2px;
   background-color: #666;
   color: #fff;
   text-decoration: none;
   font-size: 0.8em;
}

a.up:visited {
}

a.up:hover {
   background-color: #028ec9;
}
"""

## CSS for Master report
##
CSS_MASTER_REPORT = """
table {
   border-collapse: collapse;
   border-spacing: 0px;
}

td {
   margin: 0;
   border: 1px solid #fff;
   padding-top: 6px;
   padding-bottom: 6px;
   padding-left: 16px;
   padding-right: 16px;
   font-size: 0.9em;
   color: #fff;
}

table#agent_case_results {
   border-collapse: collapse;
   border-spacing: 0px;
   border-radius: 10px;
   margin-left: 20px;
   margin-right: 20px;
   margin-bottom: 40px;
}

td.outcome_desc {
   width: 100%;
   color: #333;
   font-size: 0.8em;
}

tr.agent_case_result_row a {
   color: #eee;
}

td.agent {
   color: #fff;
   font-size: 1.0em;
   text-align: center;
   background-color: #048;
   font-size: 0.8em;
   word-wrap: break-word;
   padding: 4px;
   width: 140px;
}

td.case {
   background-color: #666;
   text-align: left;
   padding-left: 40px;
   font-size: 0.9em;
}

td.case_category {
   color: #fff;
   background-color: #000;
   text-align: left;
   padding-left: 20px;
   font-size: 1.0em;
}

td.case_subcategory {
   color: #fff;
   background-color: #333;
   text-align: left;
   padding-left: 30px;
   font-size: 0.9em;
}

td.close {
   width: 15px;
   padding: 6px;
   font-size: 0.7em;
   color: #fff;
   min-width: 0px;
}

td.case_ok {
   background-color: #0a0;
   text-align: center;
}

td.case_almost {
   background-color: #6d6;
   text-align: center;
}

td.case_non_strict, td.case_no_close {
   background-color: #9a0;
   text-align: center;
}

td.case_info {
   background-color: #4095BF;
   text-align: center;
}

td.case_unimplemented {
   background-color: #800080;
   text-align: center;
}

td.case_failed {
   background-color: #900;
   text-align: center;
}

td.case_missing {
   color: #fff;
   background-color: #a05a2c;
   text-align: center;
}

span.case_duration {
   font-size: 0.7em;
   color: #fff;
}

*.unselectable {
   user-select: none;
   -moz-user-select: -moz-none;
   -webkit-user-select: none;
   -khtml-user-select: none;
}

div#toggle_button {
   position: fixed;
   bottom: 10px;
   right: 10px;
   background-color: rgba(60, 60, 60, 0.5);
   border-radius: 12px;
   color: #fff;
   font-size: 0.7em;
   padding: 5px 10px;
}

div#toggle_button:hover {
   background-color: #028ec9;
}
"""

## CSS for Agent/Case detail report
##
CSS_DETAIL_REPORT = """
p.case {
   color: #fff;
   border-radius: 10px;
   padding: 20px;
   margin: 12px 20px;
   font-size: 1.2em;
}

p.case_ok {
   background-color: #0a0;
}

p.case_non_strict, p.case_no_close {
   background-color: #9a0;
}

p.case_info {
   background-color: #4095BF;
}

p.case_failed {
   background-color: #900;
}

table {
   border-collapse: collapse;
   border-spacing: 0px;
   margin-left: 80px;
   margin-bottom: 12px;
   margin-top: 0px;
}

td
{
   margin: 0;
   font-size: 0.8em;
   border: 1px #fff solid;
   padding-top: 6px;
   padding-bottom: 6px;
   padding-left: 16px;
   padding-right: 16px;
   text-align: right;
}

td.right {
   text-align: right;
}

td.left {
   text-align: left;
}

tr.stats_header {
   color: #eee;
   background-color: #000;
}

tr.stats_row {
   color: #000;
   background-color: #fc3;
}

tr.stats_total {
   color: #fff;
   background-color: #888;
}

div#wirelog {
   margin-top: 20px;
   margin-bottom: 80px;
}

pre.wirelog_rx_octets {color: #aaa; margin: 0; background-color: #060; padding: 2px;}
pre.wirelog_tx_octets {color: #aaa; margin: 0; background-color: #600; padding: 2px;}
pre.wirelog_tx_octets_sync {color: #aaa; margin: 0; background-color: #606; padding: 2px;}

pre.wirelog_rx_frame {color: #fff; margin: 0; background-color: #0a0; padding: 2px;}
pre.wirelog_tx_frame {color: #fff; margin: 0; background-color: #a00; padding: 2px;}
pre.wirelog_tx_frame_sync {color: #fff; margin: 0; background-color: #a0a; padding: 2px;}

pre.wirelog_delay {color: #fff; margin: 0; background-color: #000; padding: 2px;}
pre.wirelog_kill_after {color: #fff; margin: 0; background-color: #000; padding: 2px;}

pre.wirelog_tcp_closed_by_me {color: #fff; margin: 0; background-color: #008; padding: 2px;}
pre.wirelog_tcp_closed_by_peer {color: #fff; margin: 0; background-color: #000; padding: 2px;}
"""

## JavaScript for master report
##
## Template vars:
##    agents_cnt => int => len(self.agents.keys())
##
JS_MASTER_REPORT = """
var isClosed = false;

function closeHelper(display,colspan) {
   // hide all close codes
   var a = document.getElementsByClassName("close_hide");
   for (var i in a) {
      if (a[i].style) {
         a[i].style.display = display;
      }
   }

   // set colspans
   var a = document.getElementsByClassName("close_flex");
   for (var i in a) {
      a[i].colSpan = colspan;
   }

   var a = document.getElementsByClassName("case_subcategory");
   for (var i in a) {
      a[i].colSpan = %(agents_cnt)d * colspan + 1;
   }
}

function toggleClose() {
   if (window.isClosed == false) {
      closeHelper("none",1);
      window.isClosed = true;
   } else {
      closeHelper("table-cell",2);
      window.isClosed = false;
   }
}
"""

REPORT_DIR_PERMISSIONS = 0770

from zope.interface import implementer
from interfaces import IReportGenerator

@implementer(IReportGenerator)
class HtmlReportGenerator(object):

    def __init__(self, test_db, report_dirname):
        self.test_db = test_db
        self.report_dirname = report_dirname
        env = jinja2.Environment(
            loader=jinja2.PackageLoader("autobahntestsuite", "templates"),
            line_statement_prefix="#",
            line_comment_prefix="##")
        self.wamp_details_tpl = env.get_template("wamp_details.html")
        self.wamp_index_tpl = env.get_template("wamp_overview.html")

        # Check if the 'reports' directory exists; try to create it otherwise.
        if not os.path.isdir(report_dirname):
            self.createReportDirectory()

    def writeReportIndexFile(self, runId, file = None):
       # return a Deferred that yields the automatically
       # choose filename if no file-like objct was provided,
       # and None otherwise
       raise Exception("implement me")

    def writeReportFile(self, resultId, file = None):
       # return a Deferred that yields the automatically
       # choose filename if no file-like objct was provided,
       # and None otherwise
       raise Exception("implement me")

    def createReportDirectory(self):
       """
       Create the directory for storing the reports. If this is not possible,
       terminate the script.
       """
       try:
          os.makedirs(self.report_dirname, REPORT_DIR_PERMISSIONS)
       except OSError, exc:
          print "Could not create directory: %s" % exc
          sys.exit(1)

    ### TODO: Move the creation of reports to a separate class.
    def createReport(self, res, report_filename, readable_test_name, agent,
                     description):
       """
       Create an HTML file called `report_filename` in the
       `report_dirname` directory with details about the test case.
       """
       report_path = os.path.join(self.report_dirname, report_filename)
       try:
          f = open(report_path, "w")
       except IOError, ex:
          print "Could not create file %s: %s." % (report_path, ex)
          return
       try:
           f.write(self.formatResultAsHtml(res, readable_test_name, agent,
                                           description))
       except Exception, ex:
           print "Could not write report: %s." % ex
       f.close()

    def formatResultAsHtml(self, res, readable_test_name, agent, description):
       """
       Create an HTML document with a table containing information about
       the test outcome.
       """
       html = self.wamp_details_tpl.render(record_list=res[3],
                                           test_name = readable_test_name,
                                           expected=res[1],
                                           observed=res[2],
                                           outcome="Pass" if res[0] else "Fail",
                                           agent=agent,
                                           description=description)
       return html

    def createIndex(self, reports):
        """
        Create an HTML document with a table containing an overview of all
        tests and links to the detailed documents.
        """
        try:
            with open(os.path.join(self.report_dirname, "index.html"),
                      "w") as f:
                html = self.wamp_index_tpl.render(categories=reports)
                f.write(html)
        except Exception, ex:
            print "Could not create index file: %s" % ex
<|endoftext|>


<commit_before>#!/usr/bin/env python
# -*- coding: utf-8 -*-

import rospy
import tf
from collections import OrderedDict

from geometry_msgs.msg import PoseStamped
from geometry_msgs.msg import Twist
from nav_msgs.msg import Odometry
from geometry_msgs.msg import Point

from referee_pb2 import SSL_Referee
import tool
import constants

class Command(object):
    def __init__(self):
        self.target_pose = PoseStamped()
        self.target_velocity = Twist()
        self.aim = Point()
        self.kick_power = 0.0
        self.dribble_power = 0.0
        self.velocity_control_enable = False
        self.chip_enable = False
        self.navigation_enable = False

    def set_target_pose(self, x, y, yaw, frame_id):
        self.target_pose.header.stamp = rospy.Time()
        self.target_pose.header.frame_id = frame_id

        self.target_pose.pose.position.x = x;
        self.target_pose.pose.position.y = y;

        quaternion = tf.transformations.quaternion_from_euler(0.0, 0.0, yaw)
        self.target_pose.pose.orientation.x = quaternion[0]
        self.target_pose.pose.orientation.y = quaternion[1]
        self.target_pose.pose.orientation.z = quaternion[2]
        self.target_pose.pose.orientation.w = quaternion[3]

        self.velocity_control_enable = False

    def set_target_velocity(self, vx, vy, vyaw):
        self.target_velocity.linear.x = vx;
        self.target_velocity.linear.y = vy;
        self.target_velocity.angular.z = vyaw;
        self.velocity_control_enable = True

    def set_aim(self, x, y):
        self.aim.x = x
        self.aim.y = y

class WorldModel(object):
    situations = {'HALT' : False, 'STOP' : False, 'FORCE_START' : False,
            'OUR_KICKOFF_PRE' : False, 'OUR_KICKOFF_START' : False,
            'OUR_PENALTY_PRE' : False, 'OUR_PENALTY_START' : False,
            'OUR_DIRECT' : False, 'OUR_INDIRECT' : False,
            'OUR_TIMEOUT' : False,
            'THEIR_KICKOFF' : False, 'THEIR_KICKOFF_START' : False,
            'THEIR_PENALTY' : False, 'THEIR_PENALTY_START' : False,
            'THEIR_DIRECT' : False, 'THEIR_INDIRECT' : False,
            'THEIR_TIMEOUT' : False}

    recent_situations = {'BALL_MOVED' : False, 'OUR_ROBOT_CHANGED' : False}
    current_situation = 'HALT'

    assignments = OrderedDict()
    assignments['Role_0'] = None
    assignments['Role_1'] = None
    assignments['Role_2'] = None
    assignments['Role_3'] = None
    assignments['Role_4'] = None
    assignments['Role_5'] = None

    commands = {'Role_0' : Command(), 'Role_1' : Command(),
                'Role_2' : Command(), 'Role_3' : Command(),
                'Role_4' : Command(), 'Role_5' : Command()}

    ball_odom = Odometry()

    friend_goalie_id = 0
    friend_color = 'blue'
    friend_odoms = [Odometry()] * 12
    existing_friends_id = [None] * 6

    enemy_goalie_id = 0
    enemy_odoms = [Odometry()] * 12
    existing_enemies_id = [None] * 6

    enemy_assignments = OrderedDict()
    enemy_assignments['Enemy_Goalie'] = None
    enemy_assignments['Enemy_1'] = None
    enemy_assignments['Enemy_2'] = None
    enemy_assignments['Enemy_3'] = None
    enemy_assignments['Enemy_4'] = None
    enemy_assignments['Enemy_5'] = None

    tf_listener = tf.TransformListener()

    _refbox_command = None
    _refbox_command_changed = False

    _refbox_dict_blue = {SSL_Referee.HALT : 'HALT', SSL_Referee.STOP : 'STOP',
            SSL_Referee.NORMAL_START : 'NORMAL_START',
            SSL_Referee.FORCE_START : 'FORCE_START',
            SSL_Referee.PREPARE_KICKOFF_BLUE : 'OUR_KICKOFF_PRE',
            SSL_Referee.PREPARE_PENALTY_BLUE : 'OUR_PENALTY_PRE',
            SSL_Referee.DIRECT_FREE_BLUE : 'OUR_DIRECT',
            SSL_Referee.INDIRECT_FREE_BLUE : 'OUR_INDIRECT',
            SSL_Referee.TIMEOUT_BLUE : 'OUR_TIMEOUT',
            SSL_Referee.PREPARE_KICKOFF_YELLOW : 'THEIR_KICKOFF_PRE',
            SSL_Referee.PREPARE_PENALTY_YELLOW : 'THEIR_PENALTY_PRE',
            SSL_Referee.DIRECT_FREE_YELLOW : 'THEIR_DIRECT',
            SSL_Referee.INDIRECT_FREE_YELLOW : 'THEIR_INDIRECT',
            SSL_Referee.TIMEOUT_YELLOW : 'THEIR_TIMEOUT'}

    _refbox_dict_yellow = {SSL_Referee.HALT : 'HALT', SSL_Referee.STOP : 'STOP',
            SSL_Referee.NORMAL_START : 'NORMAL_START',
            SSL_Referee.FORCE_START : 'FORCE_START',
            SSL_Referee.PREPARE_KICKOFF_BLUE : 'THEIR_KICKOFF_PRE',
            SSL_Referee.PREPARE_PENALTY_BLUE : 'THEIR_PENALTY_PRE',
            SSL_Referee.DIRECT_FREE_BLUE : 'THEIR_DIRECT',
            SSL_Referee.INDIRECT_FREE_BLUE : 'THEIR_INDIRECT',
            SSL_Referee.TIMEOUT_BLUE : 'THEIR_TIMEOUT',
            SSL_Referee.PREPARE_KICKOFF_YELLOW : 'OUR_KICKOFF_PRE',
            SSL_Referee.PREPARE_PENALTY_YELLOW : 'OUR_PENALTY_PRE',
            SSL_Referee.DIRECT_FREE_YELLOW : 'OUR_DIRECT',
            SSL_Referee.INDIRECT_FREE_YELLOW : 'OUR_INDIRECT',
            SSL_Referee.TIMEOUT_YELLOW : 'OUR_TIMEOUT'}
    _refbox_dict = _refbox_dict_blue

    @classmethod
    def update_world(cls):
        WorldModel._update_situation()

        WorldModel._update_enemy_assignments()

    @classmethod
    def reset_recent_situations(cls):
        pass

    @classmethod
    def update_assignments(cls):
        unassigned_roles, unassigned_IDs = WorldModel._check_unassignment()

        # Goalie_IDはRole_0に固定する
        if WorldModel.friend_goalie_id in unassigned_IDs:
            WorldModel.assignments['Role_0'] = WorldModel.friend_goalie_id
            unassigned_IDs.remove(WorldModel.friend_goalie_id)
            unassigned_roles.remove('Role_0')

        for role in unassigned_roles:
            if unassigned_IDs and role != 'Role_0':
                WorldModel.assignments[role] = unassigned_IDs.pop()
            else:
                WorldModel.assignments[role] = None

    @classmethod
    def set_friend_color(cls, data):
        WorldModel.friend_color = data
        if data == 'blue':
            WorldModel._refbox_dict = WorldModel._refbox_dict_blue
        elif data == 'yellow':
            WorldModel._refbox_dict = WorldModel._refbox_dict_yellow

    @classmethod
    def set_existing_friends_id(cls, data):
        WorldModel.existing_friends_id  = list(data)

    @classmethod
    def set_existing_enemies_id(cls, data):
        WorldModel.existing_enemies_id = list(data)

    @classmethod
    def set_refbox_command(cls, data):
        if WorldModel._refbox_command != data:
            WorldModel._refbox_command_changed = True
            WorldModel._refbox_command = data

    @classmethod
    def get_pose(cls, name):
        point = Point(0,0,0)

        if name == 'Ball':
            ball_pose = WorldModel.ball_odom.pose.pose.position
            point = Point(ball_pose.x, ball_pose.y, 0)

        elif name[:4] == 'Role':
            point = WorldModel.get_friend_pose(name)

        elif name[:5] == 'Enemy':
            point = WorldModel.get_enemy_pose(name)

        elif name[:5] == 'CONST':
            point = constants.poses[name]

        return point

    @classmethod
    def get_friend_pose(cls, role):
        robot_id = WorldModel.assignments[role]

        if robot_id is None:
            return None

        position = WorldModel.friend_odoms[robot_id].pose.pose.position
        orientation = WorldModel.friend_odoms[robot_id].pose.pose.orientation
        yaw = tool.yawFromQuaternion(orientation)

        return Point(position.x, position.y, yaw)

    @classmethod
    def get_enemy_pose(cls, role):
        robot_id = WorldModel.enemy_assignments[role]

        if robot_id is None:
            return None

        position = WorldModel.enemy_odoms[robot_id].pose.pose.position
        orientation = WorldModel.enemy_odoms[robot_id].pose.pose.orientation
        yaw = tool.yawFromQuaternion(orientation)

        return Point(position.x, position.y, yaw)

    @classmethod
    def _check_unassignment(cls):
        unassigned_roles = []
        unassigned_IDs = WorldModel.existing_friends_id

        for role, robot_id in WorldModel.assignments.items():
            # IDがアサインされていないRoleを取り出す
            if robot_id is None:
                unassigned_roles.append(role)

            # アサインされてるIDが存在しないRoleを取り出す
            elif not robot_id in unassigned_IDs:
                unassigned_roles.append(role)

            # アサインされてるIDが存在したら、unassigned_IDsから取り出す
            elif robot_id in unassigned_IDs:
                unassigned_IDs.remove(robot_id)

        return unassigned_roles, unassigned_IDs

    @classmethod
    def _update_enemy_assignments(cls):
        raw_id_list = list(WorldModel.existing_enemies_id)

        # enemy_assignmnetsを初期化
        for key in WorldModel.enemy_assignments.keys():
            WorldModel.enemy_assignments[key] = None

        # raw listからgoalieのIDを取り除く
        if WorldModel.enemy_goalie_id in raw_id_list:
            raw_id_list.remove(WorldModel.enemy_goalie_id)
            WorldModel.enemy_assignments['Enemy_Goalie'] = WorldModel.enemy_goalie_id

        key_i = 1
        for enemy_id in raw_id_list:
            key = 'Enemy_' + str(key_i)
            WorldModel.enemy_assignments[key] = enemy_id
            key_i += 1

    @classmethod
    def _update_situation(cls):
        if WorldModel._refbox_command_changed:
            WorldModel._refbox_command_changed = False
            WorldModel.situations[WorldModel.current_situation] = False

            refbox_command = WorldModel._refbox_dict[WorldModel._refbox_command]

            # NORMAL_STARTはKICKOFFとPENALTYのトリガーになるため、その切り分けを行う
            if refbox_command == 'NORMAL_START':
                if WorldModel.current_situation == 'OUR_KICKOFF_PRE':
                    WorldModel.current_situation = 'OUR_KICKOFF_START'

                elif WorldModel.current_situation == 'OUR_PENALTY_PRE':
                    WorldModel.current_situation = 'OUR_PENALTY_START'

                elif WorldModel.current_situation == 'THEIR_KICKOFF_PRE':
                    WorldModel.current_situation = 'THEIR_KICKOFF_START'

                elif WorldModel.current_situation == 'THEIR_PENALTY_PRE':
                    WorldModel.current_situation = 'THEIR_PENALTY_START'

                else:
                    WorldModel.current_situation = 'FORCE_START'
            else:
                WorldModel.current_situation = refbox_command

            WorldModel.situations[refbox_command] = True

<commit_msg>見方ロボットのAssignmentをID昇順に変更<commit_after>#!/usr/bin/env python
# -*- coding: utf-8 -*-

import rospy
import tf
from collections import OrderedDict

from geometry_msgs.msg import PoseStamped
from geometry_msgs.msg import Twist
from nav_msgs.msg import Odometry
from geometry_msgs.msg import Point

from referee_pb2 import SSL_Referee
import tool
import constants

class Command(object):
    def __init__(self):
        self.target_pose = PoseStamped()
        self.target_velocity = Twist()
        self.aim = Point()
        self.kick_power = 0.0
        self.dribble_power = 0.0
        self.velocity_control_enable = False
        self.chip_enable = False
        self.navigation_enable = False

    def set_target_pose(self, x, y, yaw, frame_id):
        self.target_pose.header.stamp = rospy.Time()
        self.target_pose.header.frame_id = frame_id

        self.target_pose.pose.position.x = x;
        self.target_pose.pose.position.y = y;

        quaternion = tf.transformations.quaternion_from_euler(0.0, 0.0, yaw)
        self.target_pose.pose.orientation.x = quaternion[0]
        self.target_pose.pose.orientation.y = quaternion[1]
        self.target_pose.pose.orientation.z = quaternion[2]
        self.target_pose.pose.orientation.w = quaternion[3]

        self.velocity_control_enable = False

    def set_target_velocity(self, vx, vy, vyaw):
        self.target_velocity.linear.x = vx;
        self.target_velocity.linear.y = vy;
        self.target_velocity.angular.z = vyaw;
        self.velocity_control_enable = True

    def set_aim(self, x, y):
        self.aim.x = x
        self.aim.y = y

class WorldModel(object):
    situations = {'HALT' : False, 'STOP' : False, 'FORCE_START' : False,
            'OUR_KICKOFF_PRE' : False, 'OUR_KICKOFF_START' : False,
            'OUR_PENALTY_PRE' : False, 'OUR_PENALTY_START' : False,
            'OUR_DIRECT' : False, 'OUR_INDIRECT' : False,
            'OUR_TIMEOUT' : False,
            'THEIR_KICKOFF' : False, 'THEIR_KICKOFF_START' : False,
            'THEIR_PENALTY' : False, 'THEIR_PENALTY_START' : False,
            'THEIR_DIRECT' : False, 'THEIR_INDIRECT' : False,
            'THEIR_TIMEOUT' : False}

    recent_situations = {'BALL_MOVED' : False, 'OUR_ROBOT_CHANGED' : False}
    current_situation = 'HALT'

    assignments = OrderedDict()
    assignments['Role_0'] = None
    assignments['Role_1'] = None
    assignments['Role_2'] = None
    assignments['Role_3'] = None
    assignments['Role_4'] = None
    assignments['Role_5'] = None

    commands = {'Role_0' : Command(), 'Role_1' : Command(),
                'Role_2' : Command(), 'Role_3' : Command(),
                'Role_4' : Command(), 'Role_5' : Command()}

    ball_odom = Odometry()

    friend_goalie_id = 0
    friend_color = 'blue'
    friend_odoms = [Odometry()] * 12
    existing_friends_id = [None] * 6

    enemy_goalie_id = 0
    enemy_odoms = [Odometry()] * 12
    existing_enemies_id = [None] * 6

    enemy_assignments = OrderedDict()
    enemy_assignments['Enemy_Goalie'] = None
    enemy_assignments['Enemy_1'] = None
    enemy_assignments['Enemy_2'] = None
    enemy_assignments['Enemy_3'] = None
    enemy_assignments['Enemy_4'] = None
    enemy_assignments['Enemy_5'] = None

    tf_listener = tf.TransformListener()

    _refbox_command = None
    _refbox_command_changed = False

    _refbox_dict_blue = {SSL_Referee.HALT : 'HALT', SSL_Referee.STOP : 'STOP',
            SSL_Referee.NORMAL_START : 'NORMAL_START',
            SSL_Referee.FORCE_START : 'FORCE_START',
            SSL_Referee.PREPARE_KICKOFF_BLUE : 'OUR_KICKOFF_PRE',
            SSL_Referee.PREPARE_PENALTY_BLUE : 'OUR_PENALTY_PRE',
            SSL_Referee.DIRECT_FREE_BLUE : 'OUR_DIRECT',
            SSL_Referee.INDIRECT_FREE_BLUE : 'OUR_INDIRECT',
            SSL_Referee.TIMEOUT_BLUE : 'OUR_TIMEOUT',
            SSL_Referee.PREPARE_KICKOFF_YELLOW : 'THEIR_KICKOFF_PRE',
            SSL_Referee.PREPARE_PENALTY_YELLOW : 'THEIR_PENALTY_PRE',
            SSL_Referee.DIRECT_FREE_YELLOW : 'THEIR_DIRECT',
            SSL_Referee.INDIRECT_FREE_YELLOW : 'THEIR_INDIRECT',
            SSL_Referee.TIMEOUT_YELLOW : 'THEIR_TIMEOUT'}

    _refbox_dict_yellow = {SSL_Referee.HALT : 'HALT', SSL_Referee.STOP : 'STOP',
            SSL_Referee.NORMAL_START : 'NORMAL_START',
            SSL_Referee.FORCE_START : 'FORCE_START',
            SSL_Referee.PREPARE_KICKOFF_BLUE : 'THEIR_KICKOFF_PRE',
            SSL_Referee.PREPARE_PENALTY_BLUE : 'THEIR_PENALTY_PRE',
            SSL_Referee.DIRECT_FREE_BLUE : 'THEIR_DIRECT',
            SSL_Referee.INDIRECT_FREE_BLUE : 'THEIR_INDIRECT',
            SSL_Referee.TIMEOUT_BLUE : 'THEIR_TIMEOUT',
            SSL_Referee.PREPARE_KICKOFF_YELLOW : 'OUR_KICKOFF_PRE',
            SSL_Referee.PREPARE_PENALTY_YELLOW : 'OUR_PENALTY_PRE',
            SSL_Referee.DIRECT_FREE_YELLOW : 'OUR_DIRECT',
            SSL_Referee.INDIRECT_FREE_YELLOW : 'OUR_INDIRECT',
            SSL_Referee.TIMEOUT_YELLOW : 'OUR_TIMEOUT'}
    _refbox_dict = _refbox_dict_blue

    @classmethod
    def update_world(cls):
        WorldModel._update_situation()

        WorldModel._update_enemy_assignments()

    @classmethod
    def reset_recent_situations(cls):
        pass

    @classmethod
    def update_assignments(cls):
        unassigned_roles, unassigned_IDs = WorldModel._check_unassignment()

        # Goalie_IDはRole_0に固定する
        if WorldModel.friend_goalie_id in unassigned_IDs:
            WorldModel.assignments['Role_0'] = WorldModel.friend_goalie_id
            unassigned_IDs.remove(WorldModel.friend_goalie_id)
            unassigned_roles.remove('Role_0')

        for role in unassigned_roles:
            if unassigned_IDs and role != 'Role_0':
                WorldModel.assignments[role] = unassigned_IDs.pop(0)
            else:
                WorldModel.assignments[role] = None

    @classmethod
    def set_friend_color(cls, data):
        WorldModel.friend_color = data
        if data == 'blue':
            WorldModel._refbox_dict = WorldModel._refbox_dict_blue
        elif data == 'yellow':
            WorldModel._refbox_dict = WorldModel._refbox_dict_yellow

    @classmethod
    def set_existing_friends_id(cls, data):
        WorldModel.existing_friends_id  = list(data)

    @classmethod
    def set_existing_enemies_id(cls, data):
        WorldModel.existing_enemies_id = list(data)

    @classmethod
    def set_refbox_command(cls, data):
        if WorldModel._refbox_command != data:
            WorldModel._refbox_command_changed = True
            WorldModel._refbox_command = data

    @classmethod
    def get_pose(cls, name):
        point = Point(0,0,0)

        if name == 'Ball':
            ball_pose = WorldModel.ball_odom.pose.pose.position
            point = Point(ball_pose.x, ball_pose.y, 0)

        elif name[:4] == 'Role':
            point = WorldModel.get_friend_pose(name)

        elif name[:5] == 'Enemy':
            point = WorldModel.get_enemy_pose(name)

        elif name[:5] == 'CONST':
            point = constants.poses[name]

        return point

    @classmethod
    def get_friend_pose(cls, role):
        robot_id = WorldModel.assignments[role]

        if robot_id is None:
            return None

        position = WorldModel.friend_odoms[robot_id].pose.pose.position
        orientation = WorldModel.friend_odoms[robot_id].pose.pose.orientation
        yaw = tool.yawFromQuaternion(orientation)

        return Point(position.x, position.y, yaw)

    @classmethod
    def get_enemy_pose(cls, role):
        robot_id = WorldModel.enemy_assignments[role]

        if robot_id is None:
            return None

        position = WorldModel.enemy_odoms[robot_id].pose.pose.position
        orientation = WorldModel.enemy_odoms[robot_id].pose.pose.orientation
        yaw = tool.yawFromQuaternion(orientation)

        return Point(position.x, position.y, yaw)

    @classmethod
    def _check_unassignment(cls):
        unassigned_roles = []
        unassigned_IDs = WorldModel.existing_friends_id

        for role, robot_id in WorldModel.assignments.items():
            # IDがアサインされていないRoleを取り出す
            if robot_id is None:
                unassigned_roles.append(role)

            # アサインされてるIDが存在しないRoleを取り出す
            elif not robot_id in unassigned_IDs:
                unassigned_roles.append(role)

            # アサインされてるIDが存在したら、unassigned_IDsから取り出す
            elif robot_id in unassigned_IDs:
                unassigned_IDs.remove(robot_id)

        return unassigned_roles, unassigned_IDs

    @classmethod
    def _update_enemy_assignments(cls):
        raw_id_list = list(WorldModel.existing_enemies_id)

        # enemy_assignmnetsを初期化
        for key in WorldModel.enemy_assignments.keys():
            WorldModel.enemy_assignments[key] = None

        # raw listからgoalieのIDを取り除く
        if WorldModel.enemy_goalie_id in raw_id_list:
            raw_id_list.remove(WorldModel.enemy_goalie_id)
            WorldModel.enemy_assignments['Enemy_Goalie'] = WorldModel.enemy_goalie_id

        key_i = 1
        for enemy_id in raw_id_list:
            key = 'Enemy_' + str(key_i)
            WorldModel.enemy_assignments[key] = enemy_id
            key_i += 1

    @classmethod
    def _update_situation(cls):
        if WorldModel._refbox_command_changed:
            WorldModel._refbox_command_changed = False
            WorldModel.situations[WorldModel.current_situation] = False

            refbox_command = WorldModel._refbox_dict[WorldModel._refbox_command]

            # NORMAL_STARTはKICKOFFとPENALTYのトリガーになるため、その切り分けを行う
            if refbox_command == 'NORMAL_START':
                if WorldModel.current_situation == 'OUR_KICKOFF_PRE':
                    WorldModel.current_situation = 'OUR_KICKOFF_START'

                elif WorldModel.current_situation == 'OUR_PENALTY_PRE':
                    WorldModel.current_situation = 'OUR_PENALTY_START'

                elif WorldModel.current_situation == 'THEIR_KICKOFF_PRE':
                    WorldModel.current_situation = 'THEIR_KICKOFF_START'

                elif WorldModel.current_situation == 'THEIR_PENALTY_PRE':
                    WorldModel.current_situation = 'THEIR_PENALTY_START'

                else:
                    WorldModel.current_situation = 'FORCE_START'
            else:
                WorldModel.current_situation = refbox_command

            WorldModel.situations[refbox_command] = True

<|endoftext|>


<commit_before>#!/usr/bin/env python
#
# Script for producing a make.inc file from a ini-style configuration file.
#
# http://github.com/jsspencer/generic_makefile
#
# copyright (c) 2012, James Spencer.
#
# MIT license:
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
#
'''Produce a make.inc file for a specified target/configuration.

Usage: mkconfig [options] [config_file]

config_file can be either a path to a file or the name of a file in the
specified configuration directory.

If no configuration file is given then the script chooses a config file:
1) If ./make.inc exists and contains a line beginning
## mkconfig
then the remaining parameters on that line are used as argument.
Otherwise, if a .default file in the specified configuration directory
exists, it is used.

A configuration file does not need to be specified with the --ls option.

Options:
  -h, --help            show help message and exit.
  --help-long           show this help message and exit.
  -d CONFIG_DIR, --dir=CONFIG_DIR
                        Set directory containing the configuration files.
                        Default: config/.
  -g, --debug           Use the debug settings.  Default: use optimised
                        settings.
  -l, --ls              Print list of available configurations.
  -o OUT, --out=OUT     Set the output filename to which the makefile settings
                        are written.  Use -o - to write to stdout.  Default:
                        make.inc.

A platform is defined using a simple configuration file which is an ini file
consisting of three sections: main, opt and dbg.  For instance:

    [main]
    fc = gfortran
    ld = gfortran
    libs = -llapack -lblas

    [opt]
    fflags = -O3

    [dbg]
    fflags = -g

Any option not specified in the 'opt' and 'dbg' sections is inherited from the
'main' section.  The settings in 'opt' are used by default; the debug options
can be selected by passing the -g option to mkconfig.

All options are strings unless otherwise specified.  Available options are:

fc
    Set the fortran compiler.
fflags
    Set flags to be passed to the fortran compiler during compilation.
f90_module_flag
    Set the flag used by the compiler which is used to specify the directory
    where module (.mod) files are placed when created and where they should be
    searched for.
f90_module_flag_pad [boolean]
    True if a space needs to be inserted between the defined f90_module_flag
    and the corresponding directory argument.  Default: true.
cc
    Set the C compiler.
cflags
    Set flags to be passed to the C compiler during compilation.
ccd
    Set the C compiler used to generate the C dependency files.  Only required
    if cc doesn't support -MM and -MT flags.  Default: use cc.
ccdflags
    Set the flags for the c++ compiler used to generate the C++ dependency files.
    Default: -MM -MT $CFLAGS
cxx
    Set the C++ compiler.
cxxflags
    Set flags to be passed to the C++ compiler during compilation.
cxxd
    Set the C compiler used to generate the C++ dependency files.  Only required
    if cc doesn't support -MM and -MT flags.  Default: use cxx.
cxxdflags
    Set the flags for the c++ compiler used to generate the C++ dependency files.
    Default: -MM -MT $CXXFLAGS
cpp
    Set the C preprocessor to be used on Fortran source files.  If not defined
    then the Fortran compiler is used to do the preprocessing.
cppflags
    Set flags to be used in the C preprocessing step.
    C preprocessing is applied to .F90, .F, .c and .cpp files (and not .f90
    files).
ld
    Set the linker program.
ldflags
    Set flags to be passed to the linker during linking of the compiled objects.
libs
    Set libraries to be used during the linking step.
ar
    Set the archive program.  Default: ar.
arflags
    Set the flags to be passed to the archive program.  Default: -rcs.
'''

try:
    import ConfigParser as configparser
except ImportError:
    import configparser
import optparse
import os
import sys
import shlex
import pipes
import contextlib
from configurator import prepare_configuration_dictionary, configure_file

MAKEFILE_TEMPLATE = '''# Generated by mkconfig.
## mkconfig %(args)s
# Using the %(config)s %(opt_level)s configuration.
#
# Not all options need to be set.

#-----
# Config info.

# Used to create a configuration-level and optimisation-level specific
# directory in which compiled objects are placed and to uniquely name binaries.

CONFIG = %(config)s
OPT = %(opt_level)s

LUA52 = %(lua_52)s

#-----
# Compiler configuration.

# --- Preprocessor ---
# If CPP is defined, then this is used to do the preprocessing on Fortran
# source files and then the Fortran compiler is called.  If CPP is not defined,
# then CPPFLAGS is passed to the Fortran compiler and the Fortran source files
# are preprocessed and compiled in a single step.
# All C and C++ files are preprocessed and compiled in one step by the C and
# C++ compilers, with CPPFLAGS passed to the C and C++ compilers.
CPP = %(cpp)s

# Preprocessing flags
# Used for *.F, *.F90, *.c and *.cpp files.
# Note three additional defintions specific to HANDE.
CPPFLAGS += %(cppflags)s %(defs)s

# --- Fortran ---
# compiler
FC = %(fc)s
# compiler flags
FFLAGS = %(fflags)s
# flag to specify directory to put compiled .mod files (e.g. -module for ifort, -J for gfortran)
F90_MOD_FLAG = %(f90_module_flag)s

# --- C ---
# compiler
CC = %(cc)s
# compiler flags
CFLAGS = %(cflags)s
# Not all compilers (e.g. xlc) support -MM -MT that we require to produce the
# C dependencies.  Fortunately there is (usually) a version of (e.g.) gcc
# kicking around which does.  If CCD is defined, then use that to generate the
# C dependency files, otherwise CC is used.
CCD = %(ccd)s
# If very custom flags are needed for the dependencies, they should be placed
# here, and will replace the -MM -MT $CFLAGS entirely
CCDFLAGS = %(ccdflags)s

# --- C++ ---
# compiler
CXX = %(cxx)s
# compiler flags
CXXFLAGS = %(cxxflags)s
# Not all compilers (e.g. xlc++) support -MM -MT that we require to produce the
# C++ dependencies.  Fortunately there is (usually) a version of (e.g.) g++
# kicking around which does.  If CXXD is defined, then use that to generate the
# C++ dependency files, otherwise CXX is used.
CXXD = %(cxxd)s
# If very custom flags are needed for the dependencies, they should be placed
# here, and will replace the -MM -MT $CFLAGS entirely
CXXDFLAGS = %(cxxdflags)s

# --- Linker ---
# linker
LD = %(ld)s
# linker flags
LDFLAGS = %(ldflags)s
# additional libraries to link to
LIBS = %(libs)s

# --- Archiver ---
# archive program (usually ar)
AR = %(ar)s
# archive flags (usually -rcs)
ARFLAGS = %(arflags)s
'''

def parse_options(my_args):
    '''Parse command line options given in the my_args list.

Returns the options object and the path to the selected configuration file.'''
    parser = optparse.OptionParser(usage='''mkconfig [options] [config_file]

config_file can be either a path to a file or the name of a file in the
specified configuration directory.

If no configuration file is given then the .default file in the specified
configuration directory is used.

A configuration file does not need to be specified with the --ls option.''')
    parser.add_option('--help-long', dest='help_long', action='store_true',
            help='Show long error message and exit.')
    parser.add_option('-d', '--dir', default='config/', dest='config_dir',
            help='Set directory containing the configuration files. '
                 'Default: %default.')
    parser.add_option('-g', '--debug', action='store_true', default=False,
            help='Use the debug settings.  Default: use optimised settings.')
    parser.add_option('-l', '--ls', action='store_true', default=False,
            help='Print list of available configurations.')
    parser.add_option('-o', '--out', default='make.inc',
            help='Set the output filename to which the makefile settings are '
                 'written.  Use -o - to write to stdout.  Default: %default.')
    parser.add_option('-D', '--define', action='append',
            help='Add e C preprocessor #define to be passed with -D to the compiler.'
                 ' Can be used multiple times.')

    (options, args) = parser.parse_args(my_args)

    # If there are no command line arguments, try and get them from make.inc
    if len(args) == 0 and os.path.exists('./make.inc'):
        with open('./make.inc') as f:
            for l in f:
                if '## mkconfig' in l:
                    my_args += shlex.split(l)[2:]
                    my_args = list(set(my_args))
                    print("Using arguments from:")
                    print(l.strip())
                    (options, args) = parser.parse_args(my_args)
                    break

    config_file = ''

    if not options.ls and not options.help_long:
        if len(args) == 1:
            config_file = args[0]
            if not os.path.exists(config_file):
                config_file = os.path.join(options.config_dir, config_file)
        elif len(args) == 0:
            if os.path.exists(os.path.join(options.config_dir, '.default')):
                config_file = os.path.join(options.config_dir, '.default')
            else:
                print('No config file provided.')
                parser.print_help()
                sys.exit(1)
        else:
            print('Too many config files provided.')
            parser.print_help()
            sys.exit(1)

    return (options, config_file, my_args)

def list_configs(config_dir):
    '''Return the path to all config files in config_dir.

We assume only config files are in config_dir.'''
    if os.path.isdir(config_dir):
        return [os.path.join(config_dir, f) for f in os.listdir(config_dir)]
    else:
        err = 'Config directory is not a directory: %s.' % (config_dir)
        raise IOError(err)

def parse_config(config_file):
    '''Parse the configuration file config_file.'''
    parser = configparser.ConfigParser()

    valid_sections = ['main', 'opt', 'dbg']

    valid_sections_upper = [section.upper() for section in valid_sections]

    valid_options = ['fc', 'fflags', 'cc', 'cflags', 'cxx', 'cxxflags', 'ccd',
            'cxxd', 'ccdflags', 'cxxdflags', 'cpp', 'cppflags', 'ld', 'ldflags', 'libs', 'ar', 'arflags',
            'f90_module_flag', 'f90_module_flag_pad', 'lua_52']

    boolean_states = {'0': False,
            '1': True,
            'false': False,
            'no': False,
            'off': False,
            'on': True,
            'true': True,
            'yes': True}

    default_settings = dict((key, '') for key in valid_options)
    default_settings.update(
            dict(ar='ar',
                 arflags='-rcs',
                 f90_module_flag_pad='True'
                )
            )

    parser.read(config_file)

    for section in parser.sections():
        if (section not in valid_sections and
                section not in valid_sections_upper):
            err = ('Invalid section in config file %s: %s.'
                    % (config_file, section))
            raise IOError(err)

    for section in valid_sections:
        if (section not in parser.sections() and
                section.upper() not in parser.sections()):
            err = ('Section not present in config file %s: %s.'
                        % (config_file, section))
            raise IOError(err)

    if not parser.sections():
        err = 'No sections in configuration file %s.' % (config_file)
        raise IOError(err)

    config = {}

    for section in ['opt', 'dbg']:
        config[section] = default_settings.copy()
        config[section].update(parser.items('main'))
        if section in parser.sections():
            config[section].update(parser.items(section))
        elif section.upper() in parser.sections():
            config[section].update(parser.items(section.upper()))
        # Update the module flag if a space needs to be appended.
        pad = config[section].pop('f90_module_flag_pad')
        # pad is a string rather than bool; use the same comparison that
        # configparser uses to determine if pad is set to true.
        if pad.lower() not in boolean_states:
            raise ValueError('Not a boolean: %s' % pad)
        if boolean_states[pad.lower()]:
            config[section]['f90_module_flag'] += ' '

    return config

def create_makefile(config_file, args, defs, use_debug=False):
    '''Returns the makefile using the options given in the config_file.

args is the list of arguments which is re-encoded in the make.inc.
    '''
    # Select the configuration section to use.
    if use_debug:
        config = parse_config(config_file)['dbg']
        config.update(opt_level='debug')
    else:
        config = parse_config(config_file)['opt']
        config.update(opt_level='optimised')

    # Set the name in the make.inc to be the basename of the config filename.
    # Follow any links.
    if os.path.islink(config_file):
        config_name = os.path.basename(os.readlink(config_file))
    else:
        config_name = os.path.basename(config_file)

    config.update(config=config_name)

    config["args"] = " ".join(pipes.quote(s) for s in args)
    if defs:
        config["defs"] = " -D".join([""]+defs)
    else:
        config["defs"] = ""
    return (MAKEFILE_TEMPLATE % config)

@contextlib.contextmanager
def smart_open(filename=None):
    if filename and filename is not '-':
        fh = open(filename, 'w')
    else:
        fh = sys.stdout

    try:
        yield fh
    finally:
        if fh is not sys.stdout:
            fh.close()

def main(args):
    '''Main procedure.

args: list of arguments.'''

    (options, config_file, args) = parse_options(args)

    if options.help_long:
        print(__doc__)
    elif options.ls:
        configs = ', '.join(list_configs(options.config_dir))
        print('Available configurations in %s are: %s.'
                % (options.config_dir, configs))
    else:
        with smart_open(options.out) as fh:
            fh.write(create_makefile(config_file, args, options.define, options.debug))

if __name__ == '__main__':

    main(sys.argv[1:])
<commit_msg>Correct comparison to a literal string.<commit_after>#!/usr/bin/env python
#
# Script for producing a make.inc file from a ini-style configuration file.
#
# http://github.com/jsspencer/generic_makefile
#
# copyright (c) 2012, James Spencer.
#
# MIT license:
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
#
'''Produce a make.inc file for a specified target/configuration.

Usage: mkconfig [options] [config_file]

config_file can be either a path to a file or the name of a file in the
specified configuration directory.

If no configuration file is given then the script chooses a config file:
1) If ./make.inc exists and contains a line beginning
## mkconfig
then the remaining parameters on that line are used as argument.
Otherwise, if a .default file in the specified configuration directory
exists, it is used.

A configuration file does not need to be specified with the --ls option.

Options:
  -h, --help            show help message and exit.
  --help-long           show this help message and exit.
  -d CONFIG_DIR, --dir=CONFIG_DIR
                        Set directory containing the configuration files.
                        Default: config/.
  -g, --debug           Use the debug settings.  Default: use optimised
                        settings.
  -l, --ls              Print list of available configurations.
  -o OUT, --out=OUT     Set the output filename to which the makefile settings
                        are written.  Use -o - to write to stdout.  Default:
                        make.inc.

A platform is defined using a simple configuration file which is an ini file
consisting of three sections: main, opt and dbg.  For instance:

    [main]
    fc = gfortran
    ld = gfortran
    libs = -llapack -lblas

    [opt]
    fflags = -O3

    [dbg]
    fflags = -g

Any option not specified in the 'opt' and 'dbg' sections is inherited from the
'main' section.  The settings in 'opt' are used by default; the debug options
can be selected by passing the -g option to mkconfig.

All options are strings unless otherwise specified.  Available options are:

fc
    Set the fortran compiler.
fflags
    Set flags to be passed to the fortran compiler during compilation.
f90_module_flag
    Set the flag used by the compiler which is used to specify the directory
    where module (.mod) files are placed when created and where they should be
    searched for.
f90_module_flag_pad [boolean]
    True if a space needs to be inserted between the defined f90_module_flag
    and the corresponding directory argument.  Default: true.
cc
    Set the C compiler.
cflags
    Set flags to be passed to the C compiler during compilation.
ccd
    Set the C compiler used to generate the C dependency files.  Only required
    if cc doesn't support -MM and -MT flags.  Default: use cc.
ccdflags
    Set the flags for the c++ compiler used to generate the C++ dependency files.
    Default: -MM -MT $CFLAGS
cxx
    Set the C++ compiler.
cxxflags
    Set flags to be passed to the C++ compiler during compilation.
cxxd
    Set the C compiler used to generate the C++ dependency files.  Only required
    if cc doesn't support -MM and -MT flags.  Default: use cxx.
cxxdflags
    Set the flags for the c++ compiler used to generate the C++ dependency files.
    Default: -MM -MT $CXXFLAGS
cpp
    Set the C preprocessor to be used on Fortran source files.  If not defined
    then the Fortran compiler is used to do the preprocessing.
cppflags
    Set flags to be used in the C preprocessing step.
    C preprocessing is applied to .F90, .F, .c and .cpp files (and not .f90
    files).
ld
    Set the linker program.
ldflags
    Set flags to be passed to the linker during linking of the compiled objects.
libs
    Set libraries to be used during the linking step.
ar
    Set the archive program.  Default: ar.
arflags
    Set the flags to be passed to the archive program.  Default: -rcs.
'''

try:
    import ConfigParser as configparser
except ImportError:
    import configparser
import optparse
import os
import sys
import shlex
import pipes
import contextlib
from configurator import prepare_configuration_dictionary, configure_file

MAKEFILE_TEMPLATE = '''# Generated by mkconfig.
## mkconfig %(args)s
# Using the %(config)s %(opt_level)s configuration.
#
# Not all options need to be set.

#-----
# Config info.

# Used to create a configuration-level and optimisation-level specific
# directory in which compiled objects are placed and to uniquely name binaries.

CONFIG = %(config)s
OPT = %(opt_level)s

LUA52 = %(lua_52)s

#-----
# Compiler configuration.

# --- Preprocessor ---
# If CPP is defined, then this is used to do the preprocessing on Fortran
# source files and then the Fortran compiler is called.  If CPP is not defined,
# then CPPFLAGS is passed to the Fortran compiler and the Fortran source files
# are preprocessed and compiled in a single step.
# All C and C++ files are preprocessed and compiled in one step by the C and
# C++ compilers, with CPPFLAGS passed to the C and C++ compilers.
CPP = %(cpp)s

# Preprocessing flags
# Used for *.F, *.F90, *.c and *.cpp files.
# Note three additional defintions specific to HANDE.
CPPFLAGS += %(cppflags)s %(defs)s

# --- Fortran ---
# compiler
FC = %(fc)s
# compiler flags
FFLAGS = %(fflags)s
# flag to specify directory to put compiled .mod files (e.g. -module for ifort, -J for gfortran)
F90_MOD_FLAG = %(f90_module_flag)s

# --- C ---
# compiler
CC = %(cc)s
# compiler flags
CFLAGS = %(cflags)s
# Not all compilers (e.g. xlc) support -MM -MT that we require to produce the
# C dependencies.  Fortunately there is (usually) a version of (e.g.) gcc
# kicking around which does.  If CCD is defined, then use that to generate the
# C dependency files, otherwise CC is used.
CCD = %(ccd)s
# If very custom flags are needed for the dependencies, they should be placed
# here, and will replace the -MM -MT $CFLAGS entirely
CCDFLAGS = %(ccdflags)s

# --- C++ ---
# compiler
CXX = %(cxx)s
# compiler flags
CXXFLAGS = %(cxxflags)s
# Not all compilers (e.g. xlc++) support -MM -MT that we require to produce the
# C++ dependencies.  Fortunately there is (usually) a version of (e.g.) g++
# kicking around which does.  If CXXD is defined, then use that to generate the
# C++ dependency files, otherwise CXX is used.
CXXD = %(cxxd)s
# If very custom flags are needed for the dependencies, they should be placed
# here, and will replace the -MM -MT $CFLAGS entirely
CXXDFLAGS = %(cxxdflags)s

# --- Linker ---
# linker
LD = %(ld)s
# linker flags
LDFLAGS = %(ldflags)s
# additional libraries to link to
LIBS = %(libs)s

# --- Archiver ---
# archive program (usually ar)
AR = %(ar)s
# archive flags (usually -rcs)
ARFLAGS = %(arflags)s
'''

def parse_options(my_args):
    '''Parse command line options given in the my_args list.

Returns the options object and the path to the selected configuration file.'''
    parser = optparse.OptionParser(usage='''mkconfig [options] [config_file]

config_file can be either a path to a file or the name of a file in the
specified configuration directory.

If no configuration file is given then the .default file in the specified
configuration directory is used.

A configuration file does not need to be specified with the --ls option.''')
    parser.add_option('--help-long', dest='help_long', action='store_true',
            help='Show long error message and exit.')
    parser.add_option('-d', '--dir', default='config/', dest='config_dir',
            help='Set directory containing the configuration files. '
                 'Default: %default.')
    parser.add_option('-g', '--debug', action='store_true', default=False,
            help='Use the debug settings.  Default: use optimised settings.')
    parser.add_option('-l', '--ls', action='store_true', default=False,
            help='Print list of available configurations.')
    parser.add_option('-o', '--out', default='make.inc',
            help='Set the output filename to which the makefile settings are '
                 'written.  Use -o - to write to stdout.  Default: %default.')
    parser.add_option('-D', '--define', action='append',
            help='Add e C preprocessor #define to be passed with -D to the compiler.'
                 ' Can be used multiple times.')

    (options, args) = parser.parse_args(my_args)

    # If there are no command line arguments, try and get them from make.inc
    if len(args) == 0 and os.path.exists('./make.inc'):
        with open('./make.inc') as f:
            for l in f:
                if '## mkconfig' in l:
                    my_args += shlex.split(l)[2:]
                    my_args = list(set(my_args))
                    print("Using arguments from:")
                    print(l.strip())
                    (options, args) = parser.parse_args(my_args)
                    break

    config_file = ''

    if not options.ls and not options.help_long:
        if len(args) == 1:
            config_file = args[0]
            if not os.path.exists(config_file):
                config_file = os.path.join(options.config_dir, config_file)
        elif len(args) == 0:
            if os.path.exists(os.path.join(options.config_dir, '.default')):
                config_file = os.path.join(options.config_dir, '.default')
            else:
                print('No config file provided.')
                parser.print_help()
                sys.exit(1)
        else:
            print('Too many config files provided.')
            parser.print_help()
            sys.exit(1)

    return (options, config_file, my_args)

def list_configs(config_dir):
    '''Return the path to all config files in config_dir.

We assume only config files are in config_dir.'''
    if os.path.isdir(config_dir):
        return [os.path.join(config_dir, f) for f in os.listdir(config_dir)]
    else:
        err = 'Config directory is not a directory: %s.' % (config_dir)
        raise IOError(err)

def parse_config(config_file):
    '''Parse the configuration file config_file.'''
    parser = configparser.ConfigParser()

    valid_sections = ['main', 'opt', 'dbg']

    valid_sections_upper = [section.upper() for section in valid_sections]

    valid_options = ['fc', 'fflags', 'cc', 'cflags', 'cxx', 'cxxflags', 'ccd',
            'cxxd', 'ccdflags', 'cxxdflags', 'cpp', 'cppflags', 'ld', 'ldflags', 'libs', 'ar', 'arflags',
            'f90_module_flag', 'f90_module_flag_pad', 'lua_52']

    boolean_states = {'0': False,
            '1': True,
            'false': False,
            'no': False,
            'off': False,
            'on': True,
            'true': True,
            'yes': True}

    default_settings = dict((key, '') for key in valid_options)
    default_settings.update(
            dict(ar='ar',
                 arflags='-rcs',
                 f90_module_flag_pad='True'
                )
            )

    parser.read(config_file)

    for section in parser.sections():
        if (section not in valid_sections and
                section not in valid_sections_upper):
            err = ('Invalid section in config file %s: %s.'
                    % (config_file, section))
            raise IOError(err)

    for section in valid_sections:
        if (section not in parser.sections() and
                section.upper() not in parser.sections()):
            err = ('Section not present in config file %s: %s.'
                        % (config_file, section))
            raise IOError(err)

    if not parser.sections():
        err = 'No sections in configuration file %s.' % (config_file)
        raise IOError(err)

    config = {}

    for section in ['opt', 'dbg']:
        config[section] = default_settings.copy()
        config[section].update(parser.items('main'))
        if section in parser.sections():
            config[section].update(parser.items(section))
        elif section.upper() in parser.sections():
            config[section].update(parser.items(section.upper()))
        # Update the module flag if a space needs to be appended.
        pad = config[section].pop('f90_module_flag_pad')
        # pad is a string rather than bool; use the same comparison that
        # configparser uses to determine if pad is set to true.
        if pad.lower() not in boolean_states:
            raise ValueError('Not a boolean: %s' % pad)
        if boolean_states[pad.lower()]:
            config[section]['f90_module_flag'] += ' '

    return config

def create_makefile(config_file, args, defs, use_debug=False):
    '''Returns the makefile using the options given in the config_file.

args is the list of arguments which is re-encoded in the make.inc.
    '''
    # Select the configuration section to use.
    if use_debug:
        config = parse_config(config_file)['dbg']
        config.update(opt_level='debug')
    else:
        config = parse_config(config_file)['opt']
        config.update(opt_level='optimised')

    # Set the name in the make.inc to be the basename of the config filename.
    # Follow any links.
    if os.path.islink(config_file):
        config_name = os.path.basename(os.readlink(config_file))
    else:
        config_name = os.path.basename(config_file)

    config.update(config=config_name)

    config["args"] = " ".join(pipes.quote(s) for s in args)
    if defs:
        config["defs"] = " -D".join([""]+defs)
    else:
        config["defs"] = ""
    return (MAKEFILE_TEMPLATE % config)

@contextlib.contextmanager
def smart_open(filename=None):
    if filename and filename != '-':
        fh = open(filename, 'w')
    else:
        fh = sys.stdout

    try:
        yield fh
    finally:
        if fh is not sys.stdout:
            fh.close()

def main(args):
    '''Main procedure.

args: list of arguments.'''

    (options, config_file, args) = parse_options(args)

    if options.help_long:
        print(__doc__)
    elif options.ls:
        configs = ', '.join(list_configs(options.config_dir))
        print('Available configurations in %s are: %s.'
                % (options.config_dir, configs))
    else:
        with smart_open(options.out) as fh:
            fh.write(create_makefile(config_file, args, options.define, options.debug))

if __name__ == '__main__':

    main(sys.argv[1:])
<|endoftext|>