<commit_before>"""py-motmetrics - metrics for multiple object tracker (MOT) benchmarking.

Christoph Heindl, 2017
Toka, 2018
https://github.com/cheind/py-motmetrics
Fast implement by TOKA
"""

import numpy as np

def norm2squared_matrix(objs, hyps, max_d2=float('inf')):
    """Computes the squared Euclidean distance matrix between object and hypothesis points.

    Params
    ------
    objs : NxM array
        Object points of dim M in rows
    hyps : KxM array
        Hypothesis points of dim M in rows

    Kwargs
    ------
    max_d2 : float
        Maximum tolerable squared Euclidean distance. Object / hypothesis points
        with larger distance are set to np.nan signalling do-not-pair. Defaults
        to +inf

    Returns
    -------
    C : NxK array
        Distance matrix containing pairwise distances or np.nan.
    """

    objs = np.atleast_2d(objs).astype(float)
    hyps = np.atleast_2d(hyps).astype(float)

    if objs.size == 0 or hyps.size == 0:
        return np.empty((0,0))

    assert hyps.shape[1] == objs.shape[1], "Dimension mismatch"

    C = np.empty((objs.shape[0], hyps.shape[0]))

    for o in range(objs.shape[0]):
        for h in range(hyps.shape[0]):
            e = objs[o] - hyps[h]
            C[o, h] = e.dot(e)

    C[C > max_d2] = np.nan
    return C

def boxiou(a, b):
    rx1 = max(a[0], b[0])
    rx2 = min(a[0]+a[2], b[0]+b[2])
    ry1 = max(a[1], b[1])
    ry2 = min(a[1]+a[3], b[1]+b[3])
    if ry2>ry1 and rx2>rx1:
        i = (ry2-ry1)*(rx2-rx1)
        u = a[2]*a[3]+b[2]*b[3]-i
        return float(i)/u
    else: return 0.0

def iou_matrix(objs, hyps, max_iou=1.):
    """Computes 'intersection over union (IoU)' distance matrix between object and hypothesis rectangles.

    The IoU is computed as

        IoU(a,b) = 1. - isect(a, b) / union(a, b)

    where isect(a,b) is the area of intersection of two rectangles and union(a, b) the area of union. The
    IoU is bounded between zero and one. 0 when the rectangles overlap perfectly and 1 when the overlap is
    zero.

    Params
    ------
    objs : Nx4 array
        Object rectangles (x,y,w,h) in rows
    hyps : Kx4 array
        Hypothesis rectangles (x,y,w,h) in rows

    Kwargs
    ------
    max_iou : float
        Maximum tolerable overlap distance. Object / hypothesis points
        with larger distance are set to np.nan signalling do-not-pair. Defaults
        to 0.5

    Returns
    -------
    C : NxK array
        Distance matrix containing pairwise distances or np.nan.
    """

    #import time
    #st = time.time()
    objs = np.atleast_2d(objs).astype(float)
    hyps = np.atleast_2d(hyps).astype(float)
    if objs.size == 0 or hyps.size == 0:
        return np.empty((0,0))

    assert objs.shape[1] == 4
    assert hyps.shape[1] == 4

    br_objs = objs[:, :2] + objs[:, 2:]
    br_hyps = hyps[:, :2] + hyps[:, 2:]

    C = np.empty((objs.shape[0], hyps.shape[0]))

    for o in range(objs.shape[0]):
        for h in range(hyps.shape[0]):
            #isect_xy = np.maximum(objs[o, :2], hyps[h, :2])
            #isect_wh = np.maximum(np.minimum(br_objs[o], br_hyps[h]) - isect_xy, 0)
            #isect_a = isect_wh[0]*isect_wh[1]
            #union_a = objs[o, 2]*objs[o, 3] + hyps[h, 2]*hyps[h, 3] - isect_a
            #if union_a != 0:
            #    C[o, h] = 1. - isect_a / union_a
            #else:
            #    C[o, h] = np.nan
            iou = boxiou(objs[o], hyps[h])
            if 1 - iou > max_iou:
                C[o, h] = np.nan
            else:
                C[o, h] = 1 - iou

    #C[C > max_iou] = np.nan
    #print('----'*2,'done',time.time()-st)
    return C

<commit_msg>Use numpy broadcasting to compute IOU<commit_after>"""py-motmetrics - metrics for multiple object tracker (MOT) benchmarking.

Christoph Heindl, 2017
Toka, 2018
https://github.com/cheind/py-motmetrics
Fast implement by TOKA
"""

import numpy as np

def norm2squared_matrix(objs, hyps, max_d2=float('inf')):
    """Computes the squared Euclidean distance matrix between object and hypothesis points.

    Params
    ------
    objs : NxM array
        Object points of dim M in rows
    hyps : KxM array
        Hypothesis points of dim M in rows

    Kwargs
    ------
    max_d2 : float
        Maximum tolerable squared Euclidean distance. Object / hypothesis points
        with larger distance are set to np.nan signalling do-not-pair. Defaults
        to +inf

    Returns
    -------
    C : NxK array
        Distance matrix containing pairwise distances or np.nan.
    """

    objs = np.atleast_2d(objs).astype(float)
    hyps = np.atleast_2d(hyps).astype(float)

    if objs.size == 0 or hyps.size == 0:
        return np.empty((0,0))

    assert hyps.shape[1] == objs.shape[1], "Dimension mismatch"

    C = np.empty((objs.shape[0], hyps.shape[0]))

    for o in range(objs.shape[0]):
        for h in range(hyps.shape[0]):
            e = objs[o] - hyps[h]
            C[o, h] = e.dot(e)

    C[C > max_d2] = np.nan
    return C

def rect_min_max(r):
    min_pt = r[..., :2]
    size = r[..., 2:]
    max_pt = min_pt + size
    return min_pt, max_pt

def boxiou(a, b):
    a_min, a_max = rect_min_max(a)
    b_min, b_max = rect_min_max(b)
    # Compute intersection.
    i_min = np.maximum(a_min, b_min)
    i_max = np.minimum(a_max, b_max)
    i_size = np.maximum(i_max - i_min, 0)
    i_vol = np.prod(i_size, axis=-1)
    # Get volume of union.
    a_size = np.maximum(a_max - a_min, 0)
    b_size = np.maximum(b_max - b_min, 0)
    a_vol = np.prod(a_size, axis=-1)
    b_vol = np.prod(b_size, axis=-1)
    u_vol = a_vol + b_vol - i_vol
    # return np.where(i_vol == 0, np.zeros_like(i_vol), i_vol / u_vol)
    # TODO: Use quiet divide here to avoid warning?
    return i_vol / u_vol

def iou_matrix(objs, hyps, max_iou=1.):
    """Computes 'intersection over union (IoU)' distance matrix between object and hypothesis rectangles.

    The IoU is computed as

        IoU(a,b) = 1. - isect(a, b) / union(a, b)

    where isect(a,b) is the area of intersection of two rectangles and union(a, b) the area of union. The
    IoU is bounded between zero and one. 0 when the rectangles overlap perfectly and 1 when the overlap is
    zero.

    Params
    ------
    objs : Nx4 array
        Object rectangles (x,y,w,h) in rows
    hyps : Kx4 array
        Hypothesis rectangles (x,y,w,h) in rows

    Kwargs
    ------
    max_iou : float
        Maximum tolerable overlap distance. Object / hypothesis points
        with larger distance are set to np.nan signalling do-not-pair. Defaults
        to 0.5

    Returns
    -------
    C : NxK array
        Distance matrix containing pairwise distances or np.nan.
    """

    if np.size(objs) == 0 or np.size(hyps) == 0:
        return np.empty((0, 0))

    objs = np.asfarray(objs)
    hyps = np.asfarray(hyps)
    assert objs.shape[1] == 4
    assert hyps.shape[1] == 4
    iou = boxiou(objs[:, None], hyps[None, :])
    dist = 1 - iou
    return np.where(dist > max_iou, np.nan, dist)
<|endoftext|>


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

from oslo.config import cfg
import six
from stevedore import driver

from zaqar.common import errors
from zaqar.common import utils
from zaqar.openstack.common import log

LOG = log.getLogger(__name__)

def dynamic_conf(uri, options):
    """Given metadata, yields a dynamic configuration.

    :param uri: pool location
    :type uri: six.text_type
    :param options: additional pool metadata
    :type options: dict
    :returns: Configuration object suitable for constructing storage
              drivers
    :rtype: oslo.config.cfg.ConfigOpts
    """
    # NOTE(cpp-cabrera): make it *very* clear to data storage
    # drivers that we are operating in a dynamic mode.
    general_opts = utils.dict_to_conf({'dynamic': True})

    # NOTE(cpp-cabrera): parse general opts: 'drivers'
    storage_type = six.moves.urllib_parse.urlparse(uri).scheme
    driver_opts = utils.dict_to_conf({'storage': storage_type})

    # NOTE(cpp-cabrera): parse storage-specific opts:
    # 'drivers:storage:{type}'
    storage_opts = utils.dict_to_conf({'uri': uri, 'options': options})
    storage_group = u'drivers:storage:%s' % storage_type

    # NOTE(cpp-cabrera): register those options!
    conf = cfg.ConfigOpts()
    conf.register_opts(general_opts)
    conf.register_opts(driver_opts, group=u'drivers')
    conf.register_opts(storage_opts, group=storage_group)
    return conf

def load_storage_driver(conf, cache, control_mode=False):
    """Loads a storage driver and returns it.

    The driver's initializer will be passed conf and cache as
    its positional args.

    :param conf: Configuration instance to use for loading the
        driver. Must include a 'drivers' group.
    :param cache: Cache instance that the driver can (optionally)
        use to reduce latency for some operations.
    :param control_mode: (Default False). Determines which
        driver type to load; if False, the data driver is
        loaded. If True, the control driver is loaded.
    """

    mode = 'control' if control_mode else 'data'
    driver_type = 'zaqar.queues.{0}.storage'.format(mode)

    try:
        mgr = driver.DriverManager(driver_type,
                                   conf['drivers'].storage,
                                   invoke_on_load=True,
                                   invoke_args=[conf, cache])

        return mgr.driver

    except RuntimeError as exc:
        LOG.exception(exc)
        raise errors.InvalidDriver(exc)

def keyify(key, iterable):
    """Make an iterator from an iterable of dicts compared with a key.

    :param key: A key exists for all dict inside the iterable object
    :param iterable: The input iterable object
    """

    class Keyed(object):
        def __init__(self, obj):
            self.obj = obj

        def __eq__(self, other):
            return self.obj[key] == other.obj[key]

        def __ne__(self, other):
            return self.obj[key] != other.obj[key]

        def __lt__(self, other):
            return self.obj[key] < other.obj[key]

        def __le__(self, other):
            return self.obj[key] <= other.obj[key]

        def __gt__(self, other):
            return self.obj[key] > other.obj[key]

        def __ge__(self, other):
            return self.obj[key] >= other.obj[key]

    for item in iterable:
        yield Keyed(item)

def can_connect(uri):
    """Given a URI, verifies whether it's possible to connect to it.

    :param uri: connection string to a storage endpoint
    :type uri: six.text_type
    :returns: True if can connect else False
    :rtype: bool
    """
    driver_type = 'zaqar.queues.data.storage'
    storage_type = six.moves.urllib.parse.urlparse(uri).scheme

    try:
        # NOTE(cabrera): create a mock configuration containing only
        # the URI field. This should be sufficient to initialize a
        # storage driver.
        conf = dynamic_conf(uri, {})
        mgr = driver.DriverManager(driver_type,
                                   storage_type,
                                   invoke_on_load=True,
                                   invoke_args=[conf, None])
        return mgr.driver.is_alive()

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

from oslo.config import cfg
import six
from stevedore import driver

from zaqar.common import errors
from zaqar.common import utils
from zaqar.openstack.common import log

LOG = log.getLogger(__name__)

def dynamic_conf(uri, options):
    """Given metadata, yields a dynamic configuration.

    :param uri: pool location
    :type uri: six.text_type
    :param options: additional pool metadata
    :type options: dict
    :returns: Configuration object suitable for constructing storage
              drivers
    :rtype: oslo.config.cfg.ConfigOpts
    """
    # NOTE(cpp-cabrera): make it *very* clear to data storage
    # drivers that we are operating in a dynamic mode.
    general_opts = utils.dict_to_conf({'dynamic': True})

    # NOTE(cpp-cabrera): parse general opts: 'drivers'
    storage_type = six.moves.urllib_parse.urlparse(uri).scheme
    driver_opts = utils.dict_to_conf({'storage': storage_type})

    # NOTE(cpp-cabrera): parse storage-specific opts:
    # 'drivers:storage:{type}'
    storage_opts = utils.dict_to_conf({'uri': uri, 'options': options})
    storage_group = u'drivers:storage:%s' % storage_type

    # NOTE(cpp-cabrera): register those options!
    conf = cfg.ConfigOpts()
    conf.register_opts(general_opts)
    conf.register_opts(driver_opts, group=u'drivers')
    conf.register_opts(storage_opts, group=storage_group)
    return conf

def load_storage_driver(conf, cache, control_mode=False):
    """Loads a storage driver and returns it.

    The driver's initializer will be passed conf and cache as
    its positional args.

    :param conf: Configuration instance to use for loading the
        driver. Must include a 'drivers' group.
    :param cache: Cache instance that the driver can (optionally)
        use to reduce latency for some operations.
    :param control_mode: (Default False). Determines which
        driver type to load; if False, the data driver is
        loaded. If True, the control driver is loaded.
    """

    mode = 'control' if control_mode else 'data'
    driver_type = 'zaqar.queues.{0}.storage'.format(mode)

    try:
        mgr = driver.DriverManager(driver_type,
                                   conf['drivers'].storage,
                                   invoke_on_load=True,
                                   invoke_args=[conf, cache])

        return mgr.driver

    except Exception as exc:
        LOG.exception(exc)
        raise errors.InvalidDriver(exc)

def keyify(key, iterable):
    """Make an iterator from an iterable of dicts compared with a key.

    :param key: A key exists for all dict inside the iterable object
    :param iterable: The input iterable object
    """

    class Keyed(object):
        def __init__(self, obj):
            self.obj = obj

        def __eq__(self, other):
            return self.obj[key] == other.obj[key]

        def __ne__(self, other):
            return self.obj[key] != other.obj[key]

        def __lt__(self, other):
            return self.obj[key] < other.obj[key]

        def __le__(self, other):
            return self.obj[key] <= other.obj[key]

        def __gt__(self, other):
            return self.obj[key] > other.obj[key]

        def __ge__(self, other):
            return self.obj[key] >= other.obj[key]

    for item in iterable:
        yield Keyed(item)

def can_connect(uri):
    """Given a URI, verifies whether it's possible to connect to it.

    :param uri: connection string to a storage endpoint
    :type uri: six.text_type
    :returns: True if can connect else False
    :rtype: bool
    """
    driver_type = 'zaqar.queues.data.storage'
    storage_type = six.moves.urllib.parse.urlparse(uri).scheme

    try:
        # NOTE(cabrera): create a mock configuration containing only
        # the URI field. This should be sufficient to initialize a
        # storage driver.
        conf = dynamic_conf(uri, {})
        mgr = driver.DriverManager(driver_type,
                                   storage_type,
                                   invoke_on_load=True,
                                   invoke_args=[conf, None])
        return mgr.driver.is_alive()

    except Exception:
        LOG.debug('Can\'t connect to: %s' % uri)
        return False
<|endoftext|>


<commit_before># Copyright 2014-2015 Ivan Kravets <me@ikravets.com>
#
# 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.

try:
    from platformio import util
except ImportError:
    import sys
    for p in sys.path:
        _new_paths = []
        for item in ("dist-packages", "site-packages"):
            if not p.endswith(item) and item in p:
                _new_paths.append(p[:p.rfind(item) + len(item)])
        if "platformio" in p:
            _new_paths.append(p[:p.rfind("platformio") - 1])

        for _p in _new_paths:
            if _p not in sys.path:
                sys.path.insert(0, _p)
        try:
            from platformio import util
            break
        except ImportError:
            pass

import json
from os import environ
from os.path import isfile, join
from time import time

from SCons.Script import (COMMAND_LINE_TARGETS, DefaultEnvironment, Exit,
                          SConscript, SConscriptChdir, Variables)

from platformio.exception import UnknownBoard

# AllowSubstExceptions()

# allow common variables from INI file
commonvars = Variables(None)
commonvars.AddVariables(
    ("BUILD_SCRIPT",),
    ("EXTRA_SCRIPT",),
    ("PIOENV",),
    ("PLATFORM",),

    # package aliases
    ("PIOPACKAGE_TOOLCHAIN",),
    ("PIOPACKAGE_UPLOADER",),

    # options
    ("FRAMEWORK",),
    ("BUILD_FLAGS",),
    ("SRC_BUILD_FLAGS",),
    ("SRC_FILTER",),
    ("LIB_DFCYCLIC",),
    ("LIB_IGNORE",),
    ("LIB_USE",),

    # board options
    ("BOARD",),
    ("BOARD_MCU",),
    ("BOARD_F_CPU",),

    # upload options
    ("UPLOAD_PORT",),
    ("UPLOAD_PROTOCOL",),
    ("UPLOAD_SPEED",)
)

DefaultEnvironment(
    tools=[
        "gcc", "g++", "as", "ar", "gnulink",
        "platformio", "pioupload", "pioar", "piomisc"
    ],
    toolpath=[join("$PIOBUILDER_DIR", "tools")],
    variables=commonvars,

    # Propagating External Environment
    ENV=environ,

    UNIX_TIME=int(time()),
    PROGNAME="program",

    PIOHOME_DIR=util.get_home_dir(),
    PROJECT_DIR=util.get_project_dir(),
    PROJECTLIB_DIR=util.get_projectlib_dir(),
    PROJECTSRC_DIR=util.get_projectsrc_dir(),
    PIOENVS_DIR=util.get_pioenvs_dir(),

    PIOBUILDER_DIR=join(util.get_source_dir(), "builder"),
    PIOPACKAGES_DIR=join("$PIOHOME_DIR", "packages"),

    BUILD_DIR=join("$PIOENVS_DIR", "$PIOENV"),
    BUILDSRC_DIR=join("$BUILD_DIR", "src"),
    LIBSOURCE_DIRS=[
        "$PROJECTLIB_DIR",
        util.get_lib_dir(),
        join("$PLATFORMFW_DIR", "libraries")
    ]
)

env = DefaultEnvironment()

if "BOARD" in env:
    try:
        env.Replace(BOARD_OPTIONS=util.get_boards(env.subst("$BOARD")))
    except UnknownBoard as e:
        env.Exit("Error: %s" % str(e))

    if "BOARD_MCU" not in env:
        env.Replace(BOARD_MCU="${BOARD_OPTIONS['build']['mcu']}")
    if "BOARD_F_CPU" not in env:
        env.Replace(BOARD_F_CPU="${BOARD_OPTIONS['build']['f_cpu']}")
    if "UPLOAD_PROTOCOL" not in env:
        env.Replace(
            UPLOAD_PROTOCOL="${BOARD_OPTIONS['upload'].get('protocol', None)}")
    if "UPLOAD_SPEED" not in env:
        env.Replace(
            UPLOAD_SPEED="${BOARD_OPTIONS['upload'].get('speed', None)}")
    if "ldscript" in env.get("BOARD_OPTIONS", {}).get("build", {}):
        env.Replace(
            LDSCRIPT_PATH=(
                env['BOARD_OPTIONS']['build']['ldscript']
                if isfile(env['BOARD_OPTIONS']['build']['ldscript'])
                else join("$PIOHOME_DIR", "packages", "ldscripts",
                          "${BOARD_OPTIONS['build']['ldscript']}")
            )
        )

    if env['PLATFORM'] != env.get("BOARD_OPTIONS", {}).get("platform"):
        Exit("Error: '%s' platform doesn't support this board. "
             "Use '%s' platform instead." % (
                 env['PLATFORM'],
                 env.get("BOARD_OPTIONS", {}).get("platform")))

for opt in ("LIB_IGNORE", "LIB_USE"):
    if opt not in env:
        continue
    env[opt] = [l.strip() for l in env[opt].split(",") if l.strip()]

if env.subst("$PIOPACKAGE_TOOLCHAIN"):
    env.PrependENVPath(
        "PATH",
        env.subst(join("$PIOPACKAGES_DIR", "$PIOPACKAGE_TOOLCHAIN", "bin"))
    )

SConscriptChdir(0)
SConscript(env.subst("$BUILD_SCRIPT"))

if environ.get("PLATFORMIO_EXTRA_SCRIPT", env.get("EXTRA_SCRIPT", None)):
    SConscript(environ.get("PLATFORMIO_EXTRA_SCRIPT", env.get("EXTRA_SCRIPT")))

if "envdump" in COMMAND_LINE_TARGETS:
    print env.Dump()
    Exit()

if "idedata" in COMMAND_LINE_TARGETS:
    print json.dumps(env.DumpIDEData())
    Exit()
<commit_msg>Improve running @PlatformIO outside virtualenv<commit_after># Copyright 2014-2015 Ivan Kravets <me@ikravets.com>
#
# 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.

try:
    from platformio import util
except ImportError:
    import sys
    for p in sys.path:
        _new_paths = []
        for item in ("dist-packages", "site-packages"):
            if not p.endswith(item) and item in p:
                _new_paths.append(p[:p.rfind(item) + len(item)])
        if "platformio" in p:
            _new_paths.append(p[:p.rfind("platformio") - 1])

        for _p in _new_paths:
            if _p not in sys.path:
                sys.path.insert(0, _p)
        try:
            from platformio import util
            import lockfile  # NOQA pylint: disable=unused-import
            break
        except ImportError:
            pass

import json
from os import environ
from os.path import isfile, join
from time import time

from SCons.Script import (COMMAND_LINE_TARGETS, DefaultEnvironment, Exit,
                          SConscript, SConscriptChdir, Variables)

from platformio.exception import UnknownBoard

# AllowSubstExceptions()

# allow common variables from INI file
commonvars = Variables(None)
commonvars.AddVariables(
    ("BUILD_SCRIPT",),
    ("EXTRA_SCRIPT",),
    ("PIOENV",),
    ("PLATFORM",),

    # package aliases
    ("PIOPACKAGE_TOOLCHAIN",),
    ("PIOPACKAGE_UPLOADER",),

    # options
    ("FRAMEWORK",),
    ("BUILD_FLAGS",),
    ("SRC_BUILD_FLAGS",),
    ("SRC_FILTER",),
    ("LIB_DFCYCLIC",),
    ("LIB_IGNORE",),
    ("LIB_USE",),

    # board options
    ("BOARD",),
    ("BOARD_MCU",),
    ("BOARD_F_CPU",),

    # upload options
    ("UPLOAD_PORT",),
    ("UPLOAD_PROTOCOL",),
    ("UPLOAD_SPEED",)
)

DefaultEnvironment(
    tools=[
        "gcc", "g++", "as", "ar", "gnulink",
        "platformio", "pioupload", "pioar", "piomisc"
    ],
    toolpath=[join("$PIOBUILDER_DIR", "tools")],
    variables=commonvars,

    # Propagating External Environment
    ENV=environ,

    UNIX_TIME=int(time()),
    PROGNAME="program",

    PIOHOME_DIR=util.get_home_dir(),
    PROJECT_DIR=util.get_project_dir(),
    PROJECTLIB_DIR=util.get_projectlib_dir(),
    PROJECTSRC_DIR=util.get_projectsrc_dir(),
    PIOENVS_DIR=util.get_pioenvs_dir(),

    PIOBUILDER_DIR=join(util.get_source_dir(), "builder"),
    PIOPACKAGES_DIR=join("$PIOHOME_DIR", "packages"),

    BUILD_DIR=join("$PIOENVS_DIR", "$PIOENV"),
    BUILDSRC_DIR=join("$BUILD_DIR", "src"),
    LIBSOURCE_DIRS=[
        "$PROJECTLIB_DIR",
        util.get_lib_dir(),
        join("$PLATFORMFW_DIR", "libraries")
    ]
)

env = DefaultEnvironment()

if "BOARD" in env:
    try:
        env.Replace(BOARD_OPTIONS=util.get_boards(env.subst("$BOARD")))
    except UnknownBoard as e:
        env.Exit("Error: %s" % str(e))

    if "BOARD_MCU" not in env:
        env.Replace(BOARD_MCU="${BOARD_OPTIONS['build']['mcu']}")
    if "BOARD_F_CPU" not in env:
        env.Replace(BOARD_F_CPU="${BOARD_OPTIONS['build']['f_cpu']}")
    if "UPLOAD_PROTOCOL" not in env:
        env.Replace(
            UPLOAD_PROTOCOL="${BOARD_OPTIONS['upload'].get('protocol', None)}")
    if "UPLOAD_SPEED" not in env:
        env.Replace(
            UPLOAD_SPEED="${BOARD_OPTIONS['upload'].get('speed', None)}")
    if "ldscript" in env.get("BOARD_OPTIONS", {}).get("build", {}):
        env.Replace(
            LDSCRIPT_PATH=(
                env['BOARD_OPTIONS']['build']['ldscript']
                if isfile(env['BOARD_OPTIONS']['build']['ldscript'])
                else join("$PIOHOME_DIR", "packages", "ldscripts",
                          "${BOARD_OPTIONS['build']['ldscript']}")
            )
        )

    if env['PLATFORM'] != env.get("BOARD_OPTIONS", {}).get("platform"):
        Exit("Error: '%s' platform doesn't support this board. "
             "Use '%s' platform instead." % (
                 env['PLATFORM'],
                 env.get("BOARD_OPTIONS", {}).get("platform")))

for opt in ("LIB_IGNORE", "LIB_USE"):
    if opt not in env:
        continue
    env[opt] = [l.strip() for l in env[opt].split(",") if l.strip()]

if env.subst("$PIOPACKAGE_TOOLCHAIN"):
    env.PrependENVPath(
        "PATH",
        env.subst(join("$PIOPACKAGES_DIR", "$PIOPACKAGE_TOOLCHAIN", "bin"))
    )

SConscriptChdir(0)
SConscript(env.subst("$BUILD_SCRIPT"))

if environ.get("PLATFORMIO_EXTRA_SCRIPT", env.get("EXTRA_SCRIPT", None)):
    SConscript(environ.get("PLATFORMIO_EXTRA_SCRIPT", env.get("EXTRA_SCRIPT")))

if "envdump" in COMMAND_LINE_TARGETS:
    print env.Dump()
    Exit()

if "idedata" in COMMAND_LINE_TARGETS:
    print json.dumps(env.DumpIDEData())
    Exit()
<|endoftext|>


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

"""
Run CIAO's celldetect tool
"""

import argparse
import os
import sys
import numpy as np

from chandra_suli import find_files
from chandra_suli.run_command import CommandRunner
from chandra_suli import logging_system

if __name__=="__main__":

    parser = argparse.ArgumentParser(description="Check to see if transient candidates are actually hot pixels")

    parser.add_argument("--masterfile",help="Name of file containing master list of all potential transients",
                        required=True, type=str)
    parser.add_argument("--ranks",help="Ranks in file that you want to run",nargs="+",required=True,type=int)
    parser.add_argument("--data_dir", help="Path to directory containing data of all obsids", required=True,
                        type=str)
    parser.add_argument("--outdir",help="Directory where output files will go",required=True, type=str)

    # Get logger for this command

    logger = logging_system.get_logger(os.path.basename(sys.argv[0]))

    # Instance the command runner

    runner = CommandRunner(logger)

    args = parser.parse_args()

    # Get data from master list
    master_data = np.array(np.recfromtxt(args.masterfile, names=True), ndmin=1)

    for rank in args.ranks:

        # index of object in question will be one less than the rank (first source is index 0, etc)
        idx = rank - 1

        obsid = master_data['Obsid'][idx]
        ccd = master_data['CCD'][idx]
        candidate = master_data['Candidate'][idx]
        tstart = master_data['Tstart'][idx]
        tstop = master_data['Tstop'][idx]
        obsid_dir = os.path.join(args.data_dir,str(obsid))

        evtfile = find_files.find_files(obsid_dir, 'ccd_%s_%s_filtered.fits' %(ccd,obsid))[0]
        regfile = find_files.find_files(obsid_dir, 'ccd_%s_%s_filtered_candidate_%s.reg' %(ccd,obsid,candidate))[0]

        regfile_name = os.path.splitext(os.path.basename(regfile))[0]
        newreg = "%s_reg.fits" %regfile_name
        newreg_path = os.path.join(args.outdir,newreg)

        cmd_line = 'ftcopy \"%s[regfilter(\'%s\') && (TIME >= %s) && (TIME <= %s)]\" %s clobber=yes '\
                   %(evtfile, regfile, tstart, tstop, newreg_path)

        runner.run(cmd_line)

        celldetect_file = '%s_celldetect.fits' %regfile_name
        celldetect_path = os.path.join(args.outdir, celldetect_file)

        cmd_line = 'celldetect %s %s clobber=yes' %(newreg_path, celldetect_path)
        runner.run(cmd_line)

<commit_msg>Change args<commit_after>#!/usr/bin/env python

"""
Run CIAO's celldetect tool
"""

import argparse
import os
import sys
import numpy as np

from chandra_suli import find_files
from chandra_suli.run_command import CommandRunner
from chandra_suli import logging_system

if __name__=="__main__":

    parser = argparse.ArgumentParser(description="Check to see if transient candidates are actually hot pixels")

    parser.add_argument("--masterfile",help="Name of file containing list of transients in this set",
                        required=True, type=str)
    parser.add_argument("--ranks",help="Ranks in file that you want to run",nargs="+",required=True,type=int)
    parser.add_argument("--data_dir", help="Path to directory containing data of all obsids", required=True,
                        type=str)
    parser.add_argument("--outdir",help="Directory where output files will go",required=True, type=str)

    # Get logger for this command

    logger = logging_system.get_logger(os.path.basename(sys.argv[0]))

    # Instance the command runner

    runner = CommandRunner(logger)

    args = parser.parse_args()

    # Get data from master list
    master_data = np.array(np.recfromtxt(args.masterfile, names=True), ndmin=1)

    for rank in args.ranks:

        # index of object in question will be one less than the rank (first source is index 0, etc)
        idx = rank - 1

        obsid = master_data['Obsid'][idx]
        ccd = master_data['CCD'][idx]
        candidate = master_data['Candidate'][idx]
        tstart = master_data['Tstart'][idx]
        tstop = master_data['Tstop'][idx]
        obsid_dir = os.path.join(args.data_dir,str(obsid))

        evtfile = find_files.find_files(obsid_dir, 'ccd_%s_%s_filtered.fits' %(ccd,obsid))[0]
        regfile = find_files.find_files(obsid_dir, 'ccd_%s_%s_filtered_candidate_%s.reg' %(ccd,obsid,candidate))[0]

        regfile_name = os.path.splitext(os.path.basename(regfile))[0]
        newreg = "%s_reg.fits" %regfile_name
        newreg_path = os.path.join(args.outdir,newreg)

        cmd_line = 'ftcopy \"%s[regfilter(\'%s\') && (TIME >= %s) && (TIME <= %s)]\" %s clobber=yes '\
                   %(evtfile, regfile, tstart, tstop, newreg_path)

        runner.run(cmd_line)

        celldetect_file = '%s_celldetect.fits' %regfile_name
        celldetect_path = os.path.join(args.outdir, celldetect_file)

        cmd_line = 'celldetect %s %s clobber=yes' %(newreg_path, celldetect_path)
        runner.run(cmd_line)

<|endoftext|>


<commit_before>"""

Generate simulated data for Experiment 5:
    - Read in data from Experiment 1
    - Move 2nd data point through 1 cycle in period to show how the sampling depends on when, in
      phase, it is observed

"""

# Standard library
import os

# Third-party
import astropy.units as u
import h5py
import numpy as np

# Project
from thejoker import Paths
paths = Paths()
from thejoker.celestialmechanics import OrbitalParams
from thejoker.data import RVData
from thejoker.units import usys

def main():

    experiment1_file = os.path.join(paths.root, "data", "experiment1.h5")
    if not os.path.exists(experiment1_file):
        raise IOError("Experiment 1 data file could not be found -- did you "
                      "run make-experiment1-data.py yet?")

    with h5py.File(experiment1_file, "r") as f:
        exp1_data = RVData.from_hdf5(f)
        exp1_opars = OrbitalParams.unpack(f['truth_vector'][:])
        exp1_orbit = exp1_opars.rv_orbit()

    # ------------------------------------------------------------------------
    # Generate Experiment 5 data

    data_t = exp1_data._t + exp1_data.t_offset
    data_std = 1 / np.sqrt(exp1_data._ivar)[:2]

    with h5py.File(os.path.join(paths.root, "data", "experiment5.h5"), "w") as f:
        for i,next_t in enumerate([[data_t[-1]+8, data_t[-1]+16],
                                  data_t[-1] + np.random.uniform(0,200,size=2)]): # MAGIC NUMBERS
            new_rv = exp1_orbit.generate_rv_curve(next_t).to(usys['speed']).value
            new_rv = np.random.normal(new_rv, data_std)

            exp5_data = RVData(t=np.concatenate((data_t, next_t)),
                               rv=np.concatenate((exp1_data._rv, new_rv)) * usys['speed'],
                               ivar=np.concatenate((exp1_data._ivar, 1/data_std**2)) * usys['speed'])

            g = f.create_group(str(i))
            exp5_data.to_hdf5(g)
            g.create_dataset('truth_vector', data=exp1_opars.pack())

if __name__ == '__main__':
    from argparse import ArgumentParser

    # Define parser object
    parser = ArgumentParser(description="")

    parser.add_argument("-s", "--seed", dest="seed", default=None,
                        type=int, help="Random number seed.")

    args = parser.parse_args()

    if args.seed is not None:
        np.random.seed(args.seed)

    main()
<commit_msg>new idea for exp5<commit_after>"""

Generate simulated data for Experiment 5:
    - Read in data from Experiment 1
    - Move 2nd data point through 1 cycle in period to show how the sampling depends on when, in
      phase, it is observed

"""

# Standard library
import os

# Third-party
import astropy.units as u
import h5py
import numpy as np

# Project
from thejoker import Paths
paths = Paths()
from thejoker.celestialmechanics import OrbitalParams
from thejoker.data import RVData
from thejoker.units import usys

def main():

    # Designer RV curves!

    opars = OrbitalParams(P=127.31*u.day, asini=22.124*u.R_sun, ecc=0.213,
                          omega=np.random.uniform(0, 2*np.pi)*u.rad,
                          phi0=np.random.uniform(0, 2*np.pi)*u.rad,
                          v0=np.random.normal(0, 30) * u.km/u.s)
    orbit = opars.rv_orbit(0)
    print("Mass function:", orbit.mf)
    print("omega:", orbit.omega.to(u.degree))
    print("phi0:", orbit.phi0.to(u.degree))
    print("v0:", orbit.v0.to(u.km/u.s))

    EPOCH = 55555. # arbitrary number
    P = opars.P.to(u.day).value[0]
    _t = np.array([0., 4.9, 4.92, 5.01]) * P
    t1 = np.concatenate((_t, [5.5 * P])) + EPOCH
    t2 = np.concatenate((_t, [5.92 * P])) + EPOCH

    rv_err = np.random.uniform(0.2, 0.3, size=t1.size) * u.km/u.s

    _rnd = np.random.normal(size=t1.size)
    rv1 = orbit.generate_rv_curve(t1) + _rnd*rv_err
    rv2 = orbit.generate_rv_curve(t2) + _rnd*rv_err

    with h5py.File(os.path.join(paths.root, "data", "experiment5.h5"), "w") as f:
        data1 = RVData(t=t1, rv=rv1, stddev=rv_err)
        data2 = RVData(t=t2, rv=rv2, stddev=rv_err)

        g = f.create_group("0")
        data1.to_hdf5(g)
        g.create_dataset('truth_vector', data=opars.pack())

        g = f.create_group("1")
        data2.to_hdf5(g)
        g.create_dataset('truth_vector', data=opars.pack())

if __name__ == '__main__':
    from argparse import ArgumentParser

    # Define parser object
    parser = ArgumentParser(description="")

    parser.add_argument("-s", "--seed", dest="seed", default=None,
                        type=int, help="Random number seed.")

    args = parser.parse_args()

    if args.seed is not None:
        np.random.seed(args.seed)

    main()
<|endoftext|>


<commit_before>from . import cdfread, cdfwrite
from .epochs import CDFepoch as cdfepoch  # noqa: F401

try:
    from .epochs_astropy import CDFAstropy as cdfastropy
    from .cdf_to_xarray import cdf_to_xarray
    from .xarray_to_cdf import xarray_to_cdf
except Exception:
    pass

from pathlib import Path

# This function determines if we are reading or writing a file

def CDF(path, cdf_spec=None, delete=False, validate=None, string_encoding='ascii'):
    path = Path(path).expanduser()

    if path.is_file():
        if delete:
            path.unlink()
            return
        else:
            return cdfread.CDF(path, validate=validate, string_encoding=string_encoding)
    else:
        return cdfwrite.CDF(path, cdf_spec=cdf_spec, delete=delete)
<commit_msg>Cool now the unit tests are broken<commit_after>from . import cdfread, cdfwrite
from .epochs import CDFepoch as cdfepoch  # noqa: F401

try:
    from .epochs_astropy import CDFAstropy as cdfastropy

except Exception:
    pass

from .cdf_to_xarray import cdf_to_xarray
from .xarray_to_cdf import xarray_to_cdf
from pathlib import Path

# This function determines if we are reading or writing a file

def CDF(path, cdf_spec=None, delete=False, validate=None, string_encoding='ascii'):
    path = Path(path).expanduser()

    if path.is_file():
        if delete:
            path.unlink()
            return
        else:
            return cdfread.CDF(path, validate=validate, string_encoding=string_encoding)
    else:
        return cdfwrite.CDF(path, cdf_spec=cdf_spec, delete=delete)
<|endoftext|>


<commit_before>import subprocess

from django.core.management import call_command
from django.core.management.base import BaseCommand

class Command(BaseCommand):

    def handle(self, *args, **options):

        call_command('collectstatic', '--noinput')
        subprocess.call(['touch', 'rdmo/wsgi.py'])
<commit_msg>fix deploy script<commit_after>import subprocess

from django.core.management import call_command
from django.core.management.base import BaseCommand

class Command(BaseCommand):

    def handle(self, *args, **options):

        call_command('collectstatic', '--noinput')
        subprocess.call(['touch', 'config/wsgi.py'])
<|endoftext|>


<commit_before>from awx.main import utils
from awx.conf.migrations._reencrypt import decrypt_field

__all__ = ['replace_aesecb_fernet']

def replace_aesecb_fernet(apps, schema_editor):
    _notification_templates(apps)
    _credentials(apps)
    _unified_jobs(apps)

def _notification_templates(apps):
    NotificationTemplate = apps.get_model('main', 'NotificationTemplate')
    for nt in NotificationTemplate.objects.all():
        for field in filter(lambda x: nt.notification_class.init_parameters[x]['type'] == "password",
                            nt.notification_class.init_parameters):
            if nt.notification_configuration[field].startswith('$encrypted$AESCBC$'):
                continue
            value = decrypt_field(nt, 'notification_configuration', subfield=field)
            nt.notification_configuration[field] = value
        nt.save()

def _credentials(apps):
    # this monkey-patch is necessary to make the implicit role generation save
    # signal use the correct Role model (the version active at this point in
    # migration, not the one at HEAD)
    orig_current_apps = utils.get_current_apps
    try:
        utils.get_current_apps = lambda: apps
        for credential in apps.get_model('main', 'Credential').objects.all():
            for field_name, value in credential.inputs.items():
                if value.startswith('$encrypted$AESCBC$'):
                    continue
                elif value.startswith('$encrypted$AES$'):
                    value = decrypt_field(credential, field_name)
                    credential.inputs[field_name] = value
            credential.save()
    finally:
        utils.get_current_apps = orig_current_apps

def _unified_jobs(apps):
    UnifiedJob = apps.get_model('main', 'UnifiedJob')
    for uj in UnifiedJob.objects.all():
        if uj.start_args is not None:
            if uj.start_args.startswith('$encrypted$AESCBC$'):
                continue
            start_args = decrypt_field(uj, 'start_args')
            uj.start_args = start_args
            uj.save()
<commit_msg>remove if AESCBC overhead<commit_after>from awx.main import utils
from awx.conf.migrations._reencrypt import decrypt_field

__all__ = ['replace_aesecb_fernet']

def replace_aesecb_fernet(apps, schema_editor):
    _notification_templates(apps)
    _credentials(apps)
    _unified_jobs(apps)

def _notification_templates(apps):
    NotificationTemplate = apps.get_model('main', 'NotificationTemplate')
    for nt in NotificationTemplate.objects.all():
        for field in filter(lambda x: nt.notification_class.init_parameters[x]['type'] == "password",
                            nt.notification_class.init_parameters):
            if nt.notification_configuration[field].startswith('$encrypted$AESCBC$'):
                continue
            value = decrypt_field(nt, 'notification_configuration', subfield=field)
            nt.notification_configuration[field] = value
        nt.save()

def _credentials(apps):
    # this monkey-patch is necessary to make the implicit role generation save
    # signal use the correct Role model (the version active at this point in
    # migration, not the one at HEAD)
    orig_current_apps = utils.get_current_apps
    try:
        utils.get_current_apps = lambda: apps
        for credential in apps.get_model('main', 'Credential').objects.all():
            for field_name, value in credential.inputs.items():
                if value.startswith('$encrypted$AES$'):
                    value = decrypt_field(credential, field_name)
                    credential.inputs[field_name] = value
            credential.save()
    finally:
        utils.get_current_apps = orig_current_apps

def _unified_jobs(apps):
    UnifiedJob = apps.get_model('main', 'UnifiedJob')
    for uj in UnifiedJob.objects.all():
        if uj.start_args is not None:
            if uj.start_args.startswith('$encrypted$AESCBC$'):
                continue
            start_args = decrypt_field(uj, 'start_args')
            uj.start_args = start_args
            uj.save()
<|endoftext|>


<commit_before>"""
An using Amazon's Thread example for motivation

http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/SampleTablesAndData.html
"""
from pynamodb.models import Model
from pynamodb.attributes import (
    UnicodeAttribute, NumberAttribute, UnicodeSetAttribute, UTCDateTimeAttribute
)
from datetime import datetime

class Thread(Model):
    table_name = 'Thread'
    forum_name = UnicodeAttribute(hash_key=True)
    subject = UnicodeAttribute(range_key=True)
    views = NumberAttribute(default=0)
    replies = NumberAttribute(default=0)
    answered = NumberAttribute(default=0)
    tags = UnicodeSetAttribute()
    last_post_datetime = UTCDateTimeAttribute()

# Create the table
Thread.create_table(read_capacity_units=1, write_capacity_units=1, wait=True)

# Create a thread
thread_item = Thread(
    'Some Forum',
    'Some Subject',
    tags=['foo', 'bar'],
    last_post_datetime=datetime.now()
)

# Save the thread
thread_item.save()

# Batch write operation
with Thread.batch_write() as batch:
    threads = []
    for x in range(100):
        thread = Thread('forum-{0}'.format(x), 'subject-{0}'.format(x))
        thread.tags = ['tag1', 'tag2']
        thread.last_post_datetime = datetime.now()
        threads.append(thread)

    for thread in threads:
        batch.save(thread)

# Batch get
item_keys = [('forum-{0}'.format(x), 'subject-{0}'.format(x) for x in range(100))]
for item in Thread.batch_get(item_keys):
    print(item)

# Scan
for item in Thread.scan():
    print(item)

# Query
for item in Thread.query('forum-1', subject__begins_with='subject'):
    print(item)
<commit_msg>Fix typo in example<commit_after>"""
An example using Amazon's Thread example for motivation

http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/SampleTablesAndData.html
"""
from pynamodb.models import Model
from pynamodb.attributes import (
    UnicodeAttribute, NumberAttribute, UnicodeSetAttribute, UTCDateTimeAttribute
)
from datetime import datetime

class Thread(Model):
    table_name = 'Thread'
    forum_name = UnicodeAttribute(hash_key=True)
    subject = UnicodeAttribute(range_key=True)
    views = NumberAttribute(default=0)
    replies = NumberAttribute(default=0)
    answered = NumberAttribute(default=0)
    tags = UnicodeSetAttribute()
    last_post_datetime = UTCDateTimeAttribute()

# Create the table
Thread.create_table(read_capacity_units=1, write_capacity_units=1, wait=True)

# Create a thread
thread_item = Thread(
    'Some Forum',
    'Some Subject',
    tags=['foo', 'bar'],
    last_post_datetime=datetime.now()
)

# Save the thread
thread_item.save()

# Batch write operation
with Thread.batch_write() as batch:
    threads = []
    for x in range(100):
        thread = Thread('forum-{0}'.format(x), 'subject-{0}'.format(x))
        thread.tags = ['tag1', 'tag2']
        thread.last_post_datetime = datetime.now()
        threads.append(thread)

    for thread in threads:
        batch.save(thread)

# Batch get
item_keys = [('forum-{0}'.format(x), 'subject-{0}'.format(x) for x in range(100))]
for item in Thread.batch_get(item_keys):
    print(item)

# Scan
for item in Thread.scan():
    print(item)

# Query
for item in Thread.query('forum-1', subject__begins_with='subject'):
    print(item)
<|endoftext|>


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

# Downloads YouTube Videos and converts them via FFmpeg into mp3s.

from __future__ import unicode_literals
try:
	import youtube_dl
except ImportError:
	print("Youtube_dl not found.")
	print("Please ensure it's installed.")

YT_URL = raw_input("Youtube URL > ")
class MyLogger(object):
	def debug(self, msg):
		pass

	def warning(self, msg):
		pass

	def error(self, msg):
		print(msg)

def my_hook(d):
	if d['status'] == 'finished':
		print('Done downloading, now converting...')

ydl_opts = {
		'format': 'bestaudio/best',
		'postprocessors': [{
			'key': 'FFmpegExtractAudio',
			'preferredcodec': 'mp3',
			'preferredquality': '320',
			}],
		'logger': MyLogger(),
		'progress_hooks': [my_hook],
		}

with youtube_dl.YoutubeDL(ydl_opts) as ydl:
	ydl.download([YT_URL])

<commit_msg>	deleted:    YouTube_Downloader.py 	Youtube_Downloader.py<commit_after><|endoftext|>


<commit_before>import tkinter as tk
from collections import OrderedDict

class Grid(tk.Frame):
    """
    Creates a grid of widgets (intended to be subclassed)
    """
    def __init__(self, parent, num_of_columns: int, headers: list=None):
        """
        Initialization of the grid object

        :param parent: the tk parent element of this frame
        :param num_of_columns: the number of columns contained of the grid
        :param headers: a list containing the names of the column headers
        """
        tk.Frame.__init__(self, parent, padx=3, pady=3, borderwidth=2)
        self.grid()

        self.headers = list()
        self.rows = list()
        self.num_of_columns = num_of_columns

        # do some validation
        if headers:
            if len(headers) != num_of_columns:
                raise ValueError

            for i, element in enumerate(headers):
                label = tk.Label(self, text=str(element), relief=tk.GROOVE)
                label.grid(row=0, column=i, sticky='E,W')
                self.headers.append(label)

    def add_row(self, data: list):
        """
        Adds a row of data based on the entered data

        :param data: row of data as a list
        :return: None
        """
        raise NotImplementedError

    def _redraw(self):
        """
        Forgets the current layout and redraws with the most recent information

        :return:
        """
        for row in self.rows:
            for widget in row:
                widget.grid_forget()

        offset = 0 if not self.headers else 1
        for i, row in enumerate(self.rows):
            for j, widget in enumerate(row):
                widget.grid(row=i+offset, column=j)

    def remove_row(self, row_number: int=-1):
        """
        Removes a specified row of data

        :param row_number: the row to remove (defaults to the last row)
        :return: None
        """
        if len(self.rows) == 0:
            return

        row = self.rows.pop(row_number)
        for widget in row:
            widget.destroy()

    def clear(self):
        """
        Removes all elements of the grid

        :return: None
        """
        for i in range(len(self.rows)):
            self.remove_row(0)

class LabelGrid(Grid):
    """
    A table-like display widget
    """
    def __init__(self, parent, num_of_columns: int, headers: list=None):
        """
        Initialization of the label grid object

        :param parent: the tk parent element of this frame
        :param num_of_columns: the number of columns contained of the grid
        :param headers: a list containing the names of the column headers
        """
        super().__init__(parent, num_of_columns, headers)

    def add_row(self, data: list):
        """
        Add a row of data to the current widget

        :param data: a row of data
        :return: None
        """
        # validation
        if self.headers:
            if len(self.headers) != len(data):
                raise ValueError

        offset = 0 if not self.headers else 1
        row = list()
        for i, element in enumerate(data):
            label = tk.Label(self, text=str(element), relief=tk.GROOVE)
            label.grid(row=len(self.rows) + offset, column=i, sticky='E,W')
            row.append(label)

class EntryGrid(Grid):
    """
    Add a spreadsheet-like grid of entry widgets
    """
    def __init__(self, parent, num_of_columns: int, headers: list=None):
        """
        Initialization of the entry grid object

        :param parent: the tk parent element of this frame
        :param num_of_columns: the number of columns contained of the grid
        :param headers: a list containing the names of the column headers
        """
        super().__init__(parent, num_of_columns, headers)

    def add_row(self, data: list=None):
        """
        Add a row of data to the current widget, add a <Tab> binding to the
        last element of the last row, and set the focus at the beginning of the next row

        :param data: a row of data
        :return: None
        """
        # validation
        if self.headers and data:
            if len(self.headers) != len(data):
                raise ValueError

        offset = 0 if not self.headers else 1
        row = list()

        if data:
            for i, element in enumerate(data):
                contents = '' if element is not None else str(element)
                entry = tk.Entry(self, text=contents)
                entry.grid(row=len(self.rows) + offset, column=i, sticky='E,W')
                row.append(entry)
        else:
            for i in range(self.num_of_columns):
                entry = tk.Entry(self)
                entry.grid(row=len(self.rows) + offset, column=i, sticky='E,W')
                row.append(entry)

        self.rows.append(row)

        # clear all bindings
        for row in self.rows:
            for widget in row:
                widget.unbind('<Tab>')

        def add(e):
            self.add_row()

        last_entry = self.rows[-1][-1]
        last_entry.bind('<Tab>', add)

        e = self.rows[-1][0]
        e.focus_set()

        self._redraw()

    def _read_as_dict(self):
        """
        Read the data contained in all entries as a list of
        dictionaries with the headers as the dictionary keys

        :return: list of dicts containing all tabular data
        """
        data = list()
        for row in self.rows:
            row_data = OrderedDict()
            for i, header in enumerate(self.headers):
                row_data[header.cget('text')] = row[i].get()

            data.append(row_data)

        return data

    def _read_as_table(self):
        """
        Read the data contained in all entries as a list of
        lists containing all of the data

        :return: list of dicts containing all tabular data
        """
        rows = list()

        for row in self.rows:
            rows.append([row[i].get() for i in range(self.num_of_columns)])

        return rows

    def read(self, as_dicts=True):
        """
        Read the data from the entry fields

        :param as_dicts: True if the data is desired as a list of dicts, else False
        :return:
        """
        if as_dicts:
            return self._read_as_dict()
        else:
            return self._read_as_table()

if __name__ == '__main__':
    root = tk.Tk()

    entry_grid = EntryGrid(root, 3, ['L0', 'L1', 'L2'])
    entry_grid.grid(row=0, column=0)

    def add_row():
        row = [1, 2, 3]
        entry_grid.add_row(row)

    add_row_btn = tk.Button(text='Add Row', command=add_row)
    add_row_btn.grid(row=1, column=0)

    def remove_row():
        entry_grid.remove_row(0)

    remove_row_btn = tk.Button(text='Remove Row', command=remove_row)
    remove_row_btn.grid(row=2, column=0)

    def read():
        print(entry_grid.read(as_dicts=False))

    read_btn = tk.Button(text='Read', command=read)
    read_btn.grid(row=3, column=0)

    root.mainloop()
<commit_msg>Added key/value GUI element<commit_after>import tkinter as tk
from collections import OrderedDict

class Grid(tk.Frame):
    """
    Creates a grid of widgets (intended to be subclassed)
    """
    def __init__(self, parent, num_of_columns: int, headers: list=None, **options):
        """
        Initialization of the grid object

        :param parent: the tk parent element of this frame
        :param num_of_columns: the number of columns contained of the grid
        :param headers: a list containing the names of the column headers
        """
        tk.Frame.__init__(self, parent, padx=3, pady=3, borderwidth=2, **options)
        self.grid()

        self.headers = list()
        self.rows = list()
        self.num_of_columns = num_of_columns

        # do some validation
        if headers:
            if len(headers) != num_of_columns:
                raise ValueError

            for i, element in enumerate(headers):
                label = tk.Label(self, text=str(element), relief=tk.GROOVE)
                label.grid(row=0, column=i, sticky='E,W')
                self.headers.append(label)

    def add_row(self, data: list):
        """
        Adds a row of data based on the entered data

        :param data: row of data as a list
        :return: None
        """
        raise NotImplementedError

    def _redraw(self):
        """
        Forgets the current layout and redraws with the most recent information

        :return:
        """
        for row in self.rows:
            for widget in row:
                widget.grid_forget()

        offset = 0 if not self.headers else 1
        for i, row in enumerate(self.rows):
            for j, widget in enumerate(row):
                widget.grid(row=i+offset, column=j)

    def remove_row(self, row_number: int=-1):
        """
        Removes a specified row of data

        :param row_number: the row to remove (defaults to the last row)
        :return: None
        """
        if len(self.rows) == 0:
            return

        row = self.rows.pop(row_number)
        for widget in row:
            widget.destroy()

    def clear(self):
        """
        Removes all elements of the grid

        :return: None
        """
        for i in range(len(self.rows)):
            self.remove_row(0)

class LabelGrid(Grid):
    """
    A table-like display widget
    """
    def __init__(self, parent, num_of_columns: int, headers: list=None, **options):
        """
        Initialization of the label grid object

        :param parent: the tk parent element of this frame
        :param num_of_columns: the number of columns contained of the grid
        :param headers: a list containing the names of the column headers
        """
        super().__init__(parent, num_of_columns, headers, **options)

    def add_row(self, data: list):
        """
        Add a row of data to the current widget

        :param data: a row of data
        :return: None
        """
        # validation
        if self.headers:
            if len(self.headers) != len(data):
                raise ValueError

        offset = 0 if not self.headers else 1
        row = list()
        for i, element in enumerate(data):
            label = tk.Label(self, text=str(element), relief=tk.GROOVE)
            label.grid(row=len(self.rows) + offset, column=i, sticky='E,W')
            row.append(label)

class EntryGrid(Grid):
    """
    Add a spreadsheet-like grid of entry widgets
    """
    def __init__(self, parent, num_of_columns: int, headers: list=None, **options):
        """
        Initialization of the entry grid object

        :param parent: the tk parent element of this frame
        :param num_of_columns: the number of columns contained of the grid
        :param headers: a list containing the names of the column headers
        """
        super().__init__(parent, num_of_columns, headers, **options)

    def add_row(self, data: list=None):
        """
        Add a row of data to the current widget, add a <Tab> binding to the
        last element of the last row, and set the focus at the beginning of the next row

        :param data: a row of data
        :return: None
        """
        # validation
        if self.headers and data:
            if len(self.headers) != len(data):
                raise ValueError

        offset = 0 if not self.headers else 1
        row = list()

        if data:
            for i, element in enumerate(data):
                contents = '' if element is not None else str(element)
                entry = tk.Entry(self, text=contents)
                entry.grid(row=len(self.rows) + offset, column=i, sticky='E,W')
                row.append(entry)
        else:
            for i in range(self.num_of_columns):
                entry = tk.Entry(self)
                entry.grid(row=len(self.rows) + offset, column=i, sticky='E,W')
                row.append(entry)

        self.rows.append(row)

        # clear all bindings
        for row in self.rows:
            for widget in row:
                widget.unbind('<Tab>')

        def add(e):
            self.add_row()

        last_entry = self.rows[-1][-1]
        last_entry.bind('<Tab>', add)

        e = self.rows[-1][0]
        e.focus_set()

        self._redraw()

    def _read_as_dict(self):
        """
        Read the data contained in all entries as a list of
        dictionaries with the headers as the dictionary keys

        :return: list of dicts containing all tabular data
        """
        data = list()
        for row in self.rows:
            row_data = OrderedDict()
            for i, header in enumerate(self.headers):
                row_data[header.cget('text')] = row[i].get()

            data.append(row_data)

        return data

    def _read_as_table(self):
        """
        Read the data contained in all entries as a list of
        lists containing all of the data

        :return: list of dicts containing all tabular data
        """
        rows = list()

        for row in self.rows:
            rows.append([row[i].get() for i in range(self.num_of_columns)])

        return rows

    def read(self, as_dicts=True):
        """
        Read the data from the entry fields

        :param as_dicts: True if the data is desired as a list of dicts, else False
        :return:
        """
        if as_dicts:
            return self._read_as_dict()
        else:
            return self._read_as_table()

class KeyValueEntry(tk.Frame):
    """
    Creates a key-value frame so common in modern GUI
    """
    def __init__(self, parent, keys: list, defaults: list=None,
                 unit_labels: list=None, enables: list=None,
                 title=None, on_change_callback=None, **options):
        """
        Key/Value constructor

        :param parent: the parent frame
        :param keys: the keys represented
        :param defaults: default values for each key
        :param unit_labels: unit labels for each key (to the right of the value)
        :param enables: True/False for each key
        :param title: The title of the block
        :param on_change_callback: a function callback when any element is changed
        :param options: frame tk options
        """
        tk.Frame.__init__(self, parent,
                          borderwidth=2,
                          padx=5, pady=5,
                          **options)

        self.defaults = defaults

        row_offset = 0
        columns = 3 if unit_labels else 2

        if title:
            self.title = tk.Label(self, text=title)
            self.title.grid(row=row_offset, column=0, columnspan=columns)
            row_offset += 1

        def callback(event):
            on_change_callback()

        self.keys = []
        self.values = []
        self.units = []
        for i, key in enumerate(keys):
            label = tk.Label(self, text=key)
            label.grid(row=row_offset, column=0, sticky='E')
            self.keys.append(label)

            entry = tk.Entry(self)
            entry.grid(row=row_offset, column=1)
            self.values.append(entry)

            if self.defaults:
                entry.insert(0, self.defaults[i])

            if enables:
                if not enables[i]:
                    entry.config(state=tk.DISABLED)

            if unit_labels:
                unit = tk.Label(self, text=unit_labels[i])
                unit.grid(row=row_offset, column=2, sticky='W')
                self.units.append(unit)

            if on_change_callback:
                entry.bind('<Return>', callback)
                entry.bind('<Tab>', callback)

            row_offset += 1

    def reset(self):
        """
        Clears all entries

        :return: None
        """
        for i, entry in enumerate(self.values):
            entry.delete(0, tk.END)
            entry.insert(0, self.defaults[i])

    def change_enables(self, enables_list: list):
        """
        Enable/disable inputs

        :param enables_list: list containing enables for each key

        :return: None
        """
        for i, entry in enumerate(self.values):
            if enables_list[i]:
                entry.config(state=tk.NORMAL)

    def load(self, data: dict):
        """
        Load values into the key/values via dict

        :param data: dict containing the key/values that should be inserted
        :return:
        """
        for i, label in enumerate(self.keys):
            key = label.cget('text')
            if key in data.keys():
                self.values[i].delete(0, tk.END)
                self.values[i].insert(0, str(data[key]))

    def get(self):
        """
        Retrieve the GUI elements for program use

        :return: a dictionary containing all of the data from the key/value entries
        """
        data = dict()
        for label, entry in zip(self.keys, self.values):
            data[label.cget('text')] = entry.get()

        return data

if __name__ == '__main__':
    root = tk.Tk()

    entry_grid = EntryGrid(root, 3, ['L0', 'L1', 'L2'])
    entry_grid.grid(row=0, column=0)

    def add_row():
        row = [1, 2, 3]
        entry_grid.add_row(row)

    add_row_btn = tk.Button(text='Add Row', command=add_row)
    add_row_btn.grid(row=1, column=0)

    def remove_row():
        entry_grid.remove_row(0)

    remove_row_btn = tk.Button(text='Remove Row', command=remove_row)
    remove_row_btn.grid(row=2, column=0)

    def read():
        print(entry_grid.read(as_dicts=False))

    read_btn = tk.Button(text='Read', command=read)
    read_btn.grid(row=3, column=0)

    root.mainloop()
<|endoftext|>


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

###
# Copyright (c) 2002, Jeremiah Fincher
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
#   * Redistributions of source code must retain the above copyright notice,
#     this list of conditions, and the following disclaimer.
#   * Redistributions in binary form must reproduce the above copyright notice,
#     this list of conditions, and the following disclaimer in the
#     documentation and/or other materials provided with the distribution.
#   * Neither the name of the author of this software nor the name of
#     contributors to this software may be used to endorse or promote products
#     derived from this software without specific prior written consent.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
###

"""
Provides commands useful to the owner of the bot; the commands here require
their caller to have the 'owner' capability.  This plugin is loaded by default.
"""

__revision__ = "$Id$"

import fix

import gc
import os
import imp
import sys
import linecache

import log
import conf
import utils
import world
import ircdb
import irclib
import ircmsgs
import drivers
import privmsgs
import callbacks

def loadPluginModule(name):
    """Loads (and returns) the module for the plugin with the given name."""
    files = []
    for dir in conf.pluginDirs:
        try:
            files.extend(os.listdir(dir))
        except EnvironmentError:
            log.warning('Invalid plugin directory: %s', dir)
    loweredFiles = map(str.lower, files)
    try:
        index = loweredFiles.index(name.lower()+'.py')
        name = os.path.splitext(files[index])[0]
    except ValueError: # We'd rather raise the ImportError, so we'll let go...
        pass
    moduleInfo = imp.find_module(name, conf.pluginDirs)
    module = imp.load_module(name, *moduleInfo)
    if module.__name__ in sys.modules:
        sys.modules[module.__name__] = module
    linecache.checkcache()
    return module

def loadPluginClass(irc, module):
    """Loads the plugin Class from the given module into the given irc."""
    callback = module.Class()
    assert not irc.getCallback(callback.name())
    irc.addCallback(callback)
    if hasattr(callback, 'configure'):
        callback.configure(irc)

class Owner(privmsgs.CapabilityCheckingPrivmsg):
    # This plugin must be first; its priority must be lowest; otherwise odd
    # things will happen when adding callbacks.
    priority = ~sys.maxint-1 # This must be first!
    capability = 'owner'
    _srcPlugins = ('Owner', 'Misc', 'Admin', 'User', 'Channel')
    def __init__(self):
        callbacks.Privmsg.__init__(self)
        setattr(self.__class__, 'exec', self.__class__._exec)
        self.defaultPlugins = {'list': 'Misc',
                               'capabilities': 'User',
                               'addcapability': 'Admin',
                               'removecapability': 'Admin'}

    def disambiguate(self, irc, tokens, ambiguousCommands=None):
        """Disambiguates the given tokens based on the plugins loaded and
           commands available in the given irc.  Returns a dictionary of
           ambiguous commands, mapping the command to the plugins it's
           available in."""
        if ambiguousCommands is None:
            ambiguousCommands = {}
        if tokens:
            command = callbacks.canonicalName(tokens[0])
            if command in self.defaultPlugins:
                tokens.insert(0, self.defaultPlugins[command])
            else:
                cbs = callbacks.findCallbackForCommand(irc, command)
                if len(cbs) > 1:
                    names = [cb.name() for cb in cbs]
                    srcs = [name for name in names if name in self._srcPlugins]
                    if len(srcs) == 1:
                        tokens.insert(0, srcs[0])
                    else:
                        ambiguousCommands[command] = names
            for elt in tokens:
                if isinstance(elt, list):
                    self.disambiguate(irc, elt, ambiguousCommands)
        return ambiguousCommands

    def doPrivmsg(self, irc, msg):
        callbacks.Privmsg.handled = False
        callbacks.Privmsg.errored = False
        if ircdb.checkIgnored(msg.prefix):
            return
        s = callbacks.addressed(irc.nick, msg)
        if s:
            try:
                tokens = callbacks.tokenize(s)
                if tokens and isinstance(tokens[0], list):
                    s = 'The command called may not be the result ' \
                        'of a nested command.'
                    irc.queueMsg(callbacks.error(msg, s))
                    return
            except SyntaxError, e:
                callbacks.Privmsg.errored = True
                irc.queueMsg(callbacks.error(msg, str(e)))
                return
            ambiguousCommands = {}
            self.disambiguate(irc, tokens, ambiguousCommands)
            if ambiguousCommands:
                if len(ambiguousCommands) == 1: # Common case.
                    (command, names) = ambiguousCommands.popitem()
                    names.sort()
                    s = 'The command %r is available in the %s plugins.  ' \
                        'Please specify the plugin whose command you ' \
                        'wish to call by using its name as a command ' \
                        'before calling it.' % \
                        (command, utils.commaAndify(names))
                else:
                    L = []
                    for (command, names) in ambiguousCommands.iteritems():
                        names.sort()
                        L.append('The command %r is available in the %s '
                                 'plugins' %
                                 (command, utils.commaAndify(names)))
                    s = '%s; please specify from which plugins to ' \
                        'call these commands.' % '; '.join(L)
                irc.queueMsg(callbacks.error(msg, s))
            else:
                callbacks.IrcObjectProxy(irc, msg, tokens)

    def defaultplugin(self, irc, msg, args):
        """<command> [<plugin>] [--remove]

        Calls <command> from <plugin> by default, rather than complaining about
        multiple plugins providing it.  If <plugin> is not provided, shows the
        current default plugin for <command>.  If --remove is given, removes
        the current default plugin for <command>.
        """
        if '--remove' in args:
            while '--remove' in args:
                args.remove('--remove')
            remove = True
        else:
            remove = False
        (command, plugin) = privmsgs.getArgs(args, optional=1)
        command = callbacks.canonicalName(command)
        cbs = callbacks.findCallbackForCommand(irc, command)
        if not cbs:
            irc.error('That\'t not a valid command.')
            return
        if plugin:
            self.defaultPlugins[command] = plugin
        else:
            try:
                if remove:
                    del self.defaultPlugins[command]
                else:
                    L = [command]
                    d = self.disambiguate(irc, L)
                    if d:
                        raise KeyError
                    assert len(L) == 2, 'Not disambiguated!'
                    irc.reply(L[0])
            except KeyError:
                irc.error('I have no default plugin for that command.')
                return
        irc.replySuccess()

    def eval(self, irc, msg, args):
        """<expression>

        Evaluates <expression> and returns its value.
        """
        if conf.allowEval:
            s = privmsgs.getArgs(args)
            try:
                irc.reply(repr(eval(s)))
            except SyntaxError, e:
                irc.reply('%s: %r' % (utils.exnToString(e), s))
            except Exception, e:
                irc.reply(utils.exnToString(e))
        else:
            irc.error(conf.replyEvalNotAllowed)

    def _exec(self, irc, msg, args):
        """<statement>

        Execs <code>.  Returns success if it didn't raise any exceptions.
        """
        if conf.allowEval:
            s = privmsgs.getArgs(args)
            try:
                exec s
                irc.replySuccess()
            except Exception, e:
                irc.reply(utils.exnToString(e))
        else:
            irc.error(conf.replyEvalNotAllowed)

    def setconf(self, irc, msg, args):
        """[<name> [<value>]]

        Lists adjustable variables in the conf-module by default, shows the
        variable type with only the <name> argument and sets the value of the
        variable to <value> when both arguments are given.
        """
        (name, value) = privmsgs.getArgs(args, required=0, optional=2)
        if name and value:
            if conf.allowEval:
                try:
                    value = eval(value)
                except Exception, e:
                    irc.error(utils.exnToString(e))
                    return
                setattr(conf, name, value)
                irc.replySuccess()
            else:
                if name == 'allowEval':
                    irc.error('You can\'t set the value of allowEval.')
                    return
                elif name not in conf.types:
                    irc.error('I can\'t set that conf variable.')
                    return
                else:
                    converter = conf.types[name]
                    try:
                        value = converter(value)
                    except ValueError, e:
                        irc.error(str(e))
                        return
                    setattr(conf, name, value)
                    irc.replySuccess()
        elif name:
            typeNames = {conf.mystr: 'string',
                         conf.mybool: 'boolean',
                         float: 'float'}
            try:
                type = typeNames[conf.types[name]]
            except KeyError:
                irc.error('That configuration variable doesn\'t exist.')
                return
            try:
                value = getattr(conf, name)
                irc.reply('%s is a %s (%s).' % (name, type, value))
            except KeyError:
                irc.error('%s is of an unknown type.' % name)
        else:
            options = conf.types.keys()
            options.sort()
            irc.reply(', '.join(options))

    def setdefaultcapability(self, irc, msg, args):
        """<capability>

        Sets the default capability to be allowed for any command.
        """
        capability = callbacks.canonicalName(privmsgs.getArgs(args))
        conf.defaultCapabilities.add(capability)
        irc.replySuccess()

    def unsetdefaultcapability(self, irc, msg, args):
        """<capability>

        Unsets the default capability for any command.
        """
        capability = callbacks.canonicalName(privmsgs.getArgs(args))
        conf.defaultCapabilities.remove(capability)
        irc.replySuccess()

    def ircquote(self, irc, msg, args):
        """<string to be sent to the server>

        Sends the raw string given to the server.
        """
        s = privmsgs.getArgs(args)
        try:
            m = ircmsgs.IrcMsg(s)
        except Exception, e:
            irc.error(utils.exnToString(e))
        else:
            irc.queueMsg(m)

    def quit(self, irc, msg, args):
        """takes no arguments

        Exits the bot.
        """
        world.dying = True
        for driver in drivers._drivers.itervalues():
            driver.die()
        killed = sets.Set()
        for irc in world.ircs[:]:
            # The following is so callbacks don't get killed multiple times
            # when the Relay plugin is loaded:
            if id(irc.callbacks) not in killed:
                killed.add(id(irc.callbacks))
                irc.die()
        raise SystemExit, 'Quitting because I was told by %s' % msg.prefix

    def flush(self, irc, msg, args):
        """takes no arguments

        Runs all the periodic flushers in world.flushers.
        """
        world.flush()
        irc.replySuccess()

    def upkeep(self, irc, msg, args):
        """takes no arguments

        Runs the standard upkeep stuff (flushes and gc.collects()).
        """
        collected = world.upkeep()
        if gc.garbage:
            irc.reply('Garbage!  %r' % gc.garbage)
        else:
            irc.reply('%s collected.' % utils.nItems('object', collected))

    def load(self, irc, msg, args):
        """<plugin>

        Loads the plugin <plugin> from any of the directories in
        conf.pluginDirs; usually this includes the main installed directory
        and 'plugins' in the current directory.  Be sure not to have ".py" at
        the end.
        """
        name = privmsgs.getArgs(args)
        if irc.getCallback(name):
            irc.error('That module is already loaded.')
            return
        try:
            module = loadPluginModule(name)
        except ImportError, e:
            if name in str(e):
                irc.error('No plugin %s exists.' % name)
            else:
                irc.error(utils.exnToString(e))
            return
        loadPluginClass(irc, module)
        irc.replySuccess()

    def reload(self, irc, msg, args):
        """<plugin>

        Unloads and subsequently reloads the plugin by name; use the 'list'
        command to see a list of the currently loaded plugins.
        """
        name = privmsgs.getArgs(args)
        callbacks = irc.removeCallback(name)
        if callbacks:
            module = sys.modules[callbacks[0].__module__]
            if hasattr(module, 'reload'):
                x = module.reload()
            try:
                module = loadPluginModule(name)
                if hasattr(module, 'reload'):
                    module.reload(x)
                for callback in callbacks:
                    callback.die()
                    del callback
                gc.collect()
                callback = loadPluginClass(irc, module)
                irc.replySuccess()
            except ImportError:
                for callback in callbacks:
                    irc.addCallback(callback)
                irc.error('No plugin %s exists.' % name)
        else:
            irc.error('There was no callback %s.' % name)

    def unload(self, irc, msg, args):
        """<plugin>

        Unloads the callback by name; use the 'list' command to see a list
        of the currently loaded callbacks.
        """
        name = privmsgs.getArgs(args)
        callbacks = irc.removeCallback(name)
        if callbacks:
            for callback in callbacks:
                callback.die()
                del callback
            gc.collect()
            irc.replySuccess()
        else:
            irc.error('There was no callback %s' % name)

    def reconf(self, irc, msg, args):
        """takes no arguments

        Reloads the configuration files in conf.dataDir: conf/users.conf and
        conf/channels.conf, by default.
        """
        ircdb.users.reload()
        ircdb.channels.reload()
        irc.replySuccess()

Class = Owner

# vim:set shiftwidth=4 tabstop=8 expandtab textwidth=78:

<commit_msg>Simplified quit.<commit_after>#!/usr/bin/env python

###
# Copyright (c) 2002, Jeremiah Fincher
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
#   * Redistributions of source code must retain the above copyright notice,
#     this list of conditions, and the following disclaimer.
#   * Redistributions in binary form must reproduce the above copyright notice,
#     this list of conditions, and the following disclaimer in the
#     documentation and/or other materials provided with the distribution.
#   * Neither the name of the author of this software nor the name of
#     contributors to this software may be used to endorse or promote products
#     derived from this software without specific prior written consent.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
###

"""
Provides commands useful to the owner of the bot; the commands here require
their caller to have the 'owner' capability.  This plugin is loaded by default.
"""

__revision__ = "$Id$"

import fix

import gc
import os
import imp
import sys
import sets
import linecache

import log
import conf
import utils
import world
import ircdb
import irclib
import ircmsgs
import drivers
import privmsgs
import callbacks

def loadPluginModule(name):
    """Loads (and returns) the module for the plugin with the given name."""
    files = []
    for dir in conf.pluginDirs:
        try:
            files.extend(os.listdir(dir))
        except EnvironmentError:
            log.warning('Invalid plugin directory: %s', dir)
    loweredFiles = map(str.lower, files)
    try:
        index = loweredFiles.index(name.lower()+'.py')
        name = os.path.splitext(files[index])[0]
    except ValueError: # We'd rather raise the ImportError, so we'll let go...
        pass
    moduleInfo = imp.find_module(name, conf.pluginDirs)
    module = imp.load_module(name, *moduleInfo)
    if module.__name__ in sys.modules:
        sys.modules[module.__name__] = module
    linecache.checkcache()
    return module

def loadPluginClass(irc, module):
    """Loads the plugin Class from the given module into the given irc."""
    callback = module.Class()
    assert not irc.getCallback(callback.name())
    irc.addCallback(callback)
    if hasattr(callback, 'configure'):
        callback.configure(irc)

class Owner(privmsgs.CapabilityCheckingPrivmsg):
    # This plugin must be first; its priority must be lowest; otherwise odd
    # things will happen when adding callbacks.
    priority = ~sys.maxint-1 # This must be first!
    capability = 'owner'
    _srcPlugins = ('Owner', 'Misc', 'Admin', 'User', 'Channel')
    def __init__(self):
        callbacks.Privmsg.__init__(self)
        setattr(self.__class__, 'exec', self.__class__._exec)
        self.defaultPlugins = {'list': 'Misc',
                               'capabilities': 'User',
                               'addcapability': 'Admin',
                               'removecapability': 'Admin'}

    def disambiguate(self, irc, tokens, ambiguousCommands=None):
        """Disambiguates the given tokens based on the plugins loaded and
           commands available in the given irc.  Returns a dictionary of
           ambiguous commands, mapping the command to the plugins it's
           available in."""
        if ambiguousCommands is None:
            ambiguousCommands = {}
        if tokens:
            command = callbacks.canonicalName(tokens[0])
            if command in self.defaultPlugins:
                tokens.insert(0, self.defaultPlugins[command])
            else:
                cbs = callbacks.findCallbackForCommand(irc, command)
                if len(cbs) > 1:
                    names = [cb.name() for cb in cbs]
                    srcs = [name for name in names if name in self._srcPlugins]
                    if len(srcs) == 1:
                        tokens.insert(0, srcs[0])
                    else:
                        ambiguousCommands[command] = names
            for elt in tokens:
                if isinstance(elt, list):
                    self.disambiguate(irc, elt, ambiguousCommands)
        return ambiguousCommands

    def doPrivmsg(self, irc, msg):
        callbacks.Privmsg.handled = False
        callbacks.Privmsg.errored = False
        if ircdb.checkIgnored(msg.prefix):
            return
        s = callbacks.addressed(irc.nick, msg)
        if s:
            try:
                tokens = callbacks.tokenize(s)
                if tokens and isinstance(tokens[0], list):
                    s = 'The command called may not be the result ' \
                        'of a nested command.'
                    irc.queueMsg(callbacks.error(msg, s))
                    return
            except SyntaxError, e:
                callbacks.Privmsg.errored = True
                irc.queueMsg(callbacks.error(msg, str(e)))
                return
            ambiguousCommands = {}
            self.disambiguate(irc, tokens, ambiguousCommands)
            if ambiguousCommands:
                if len(ambiguousCommands) == 1: # Common case.
                    (command, names) = ambiguousCommands.popitem()
                    names.sort()
                    s = 'The command %r is available in the %s plugins.  ' \
                        'Please specify the plugin whose command you ' \
                        'wish to call by using its name as a command ' \
                        'before calling it.' % \
                        (command, utils.commaAndify(names))
                else:
                    L = []
                    for (command, names) in ambiguousCommands.iteritems():
                        names.sort()
                        L.append('The command %r is available in the %s '
                                 'plugins' %
                                 (command, utils.commaAndify(names)))
                    s = '%s; please specify from which plugins to ' \
                        'call these commands.' % '; '.join(L)
                irc.queueMsg(callbacks.error(msg, s))
            else:
                callbacks.IrcObjectProxy(irc, msg, tokens)

    def defaultplugin(self, irc, msg, args):
        """<command> [<plugin>] [--remove]

        Calls <command> from <plugin> by default, rather than complaining about
        multiple plugins providing it.  If <plugin> is not provided, shows the
        current default plugin for <command>.  If --remove is given, removes
        the current default plugin for <command>.
        """
        if '--remove' in args:
            while '--remove' in args:
                args.remove('--remove')
            remove = True
        else:
            remove = False
        (command, plugin) = privmsgs.getArgs(args, optional=1)
        command = callbacks.canonicalName(command)
        cbs = callbacks.findCallbackForCommand(irc, command)
        if not cbs:
            irc.error('That\'t not a valid command.')
            return
        if plugin:
            self.defaultPlugins[command] = plugin
        else:
            try:
                if remove:
                    del self.defaultPlugins[command]
                else:
                    L = [command]
                    d = self.disambiguate(irc, L)
                    if d:
                        raise KeyError
                    assert len(L) == 2, 'Not disambiguated!'
                    irc.reply(L[0])
            except KeyError:
                irc.error('I have no default plugin for that command.')
                return
        irc.replySuccess()

    def eval(self, irc, msg, args):
        """<expression>

        Evaluates <expression> and returns its value.
        """
        if conf.allowEval:
            s = privmsgs.getArgs(args)
            try:
                irc.reply(repr(eval(s)))
            except SyntaxError, e:
                irc.reply('%s: %r' % (utils.exnToString(e), s))
            except Exception, e:
                irc.reply(utils.exnToString(e))
        else:
            irc.error(conf.replyEvalNotAllowed)

    def _exec(self, irc, msg, args):
        """<statement>

        Execs <code>.  Returns success if it didn't raise any exceptions.
        """
        if conf.allowEval:
            s = privmsgs.getArgs(args)
            try:
                exec s
                irc.replySuccess()
            except Exception, e:
                irc.reply(utils.exnToString(e))
        else:
            irc.error(conf.replyEvalNotAllowed)

    def setconf(self, irc, msg, args):
        """[<name> [<value>]]

        Lists adjustable variables in the conf-module by default, shows the
        variable type with only the <name> argument and sets the value of the
        variable to <value> when both arguments are given.
        """
        (name, value) = privmsgs.getArgs(args, required=0, optional=2)
        if name and value:
            if conf.allowEval:
                try:
                    value = eval(value)
                except Exception, e:
                    irc.error(utils.exnToString(e))
                    return
                setattr(conf, name, value)
                irc.replySuccess()
            else:
                if name == 'allowEval':
                    irc.error('You can\'t set the value of allowEval.')
                    return
                elif name not in conf.types:
                    irc.error('I can\'t set that conf variable.')
                    return
                else:
                    converter = conf.types[name]
                    try:
                        value = converter(value)
                    except ValueError, e:
                        irc.error(str(e))
                        return
                    setattr(conf, name, value)
                    irc.replySuccess()
        elif name:
            typeNames = {conf.mystr: 'string',
                         conf.mybool: 'boolean',
                         float: 'float'}
            try:
                type = typeNames[conf.types[name]]
            except KeyError:
                irc.error('That configuration variable doesn\'t exist.')
                return
            try:
                value = getattr(conf, name)
                irc.reply('%s is a %s (%s).' % (name, type, value))
            except KeyError:
                irc.error('%s is of an unknown type.' % name)
        else:
            options = conf.types.keys()
            options.sort()
            irc.reply(', '.join(options))

    def setdefaultcapability(self, irc, msg, args):
        """<capability>

        Sets the default capability to be allowed for any command.
        """
        capability = callbacks.canonicalName(privmsgs.getArgs(args))
        conf.defaultCapabilities.add(capability)
        irc.replySuccess()

    def unsetdefaultcapability(self, irc, msg, args):
        """<capability>

        Unsets the default capability for any command.
        """
        capability = callbacks.canonicalName(privmsgs.getArgs(args))
        conf.defaultCapabilities.remove(capability)
        irc.replySuccess()

    def ircquote(self, irc, msg, args):
        """<string to be sent to the server>

        Sends the raw string given to the server.
        """
        s = privmsgs.getArgs(args)
        try:
            m = ircmsgs.IrcMsg(s)
        except Exception, e:
            irc.error(utils.exnToString(e))
        else:
            irc.queueMsg(m)

    def quit(self, irc, msg, args):
        """takes no arguments

        Exits the bot.
        """
        raise SystemExit, 'Quitting because I was told by %s' % msg.prefix

    def flush(self, irc, msg, args):
        """takes no arguments

        Runs all the periodic flushers in world.flushers.
        """
        world.flush()
        irc.replySuccess()

    def upkeep(self, irc, msg, args):
        """takes no arguments

        Runs the standard upkeep stuff (flushes and gc.collects()).
        """
        collected = world.upkeep()
        if gc.garbage:
            irc.reply('Garbage!  %r' % gc.garbage)
        else:
            irc.reply('%s collected.' % utils.nItems('object', collected))

    def load(self, irc, msg, args):
        """<plugin>

        Loads the plugin <plugin> from any of the directories in
        conf.pluginDirs; usually this includes the main installed directory
        and 'plugins' in the current directory.  Be sure not to have ".py" at
        the end.
        """
        name = privmsgs.getArgs(args)
        if irc.getCallback(name):
            irc.error('That module is already loaded.')
            return
        try:
            module = loadPluginModule(name)
        except ImportError, e:
            if name in str(e):
                irc.error('No plugin %s exists.' % name)
            else:
                irc.error(utils.exnToString(e))
            return
        loadPluginClass(irc, module)
        irc.replySuccess()

    def reload(self, irc, msg, args):
        """<plugin>

        Unloads and subsequently reloads the plugin by name; use the 'list'
        command to see a list of the currently loaded plugins.
        """
        name = privmsgs.getArgs(args)
        callbacks = irc.removeCallback(name)
        if callbacks:
            module = sys.modules[callbacks[0].__module__]
            if hasattr(module, 'reload'):
                x = module.reload()
            try:
                module = loadPluginModule(name)
                if hasattr(module, 'reload'):
                    module.reload(x)
                for callback in callbacks:
                    callback.die()
                    del callback
                gc.collect()
                callback = loadPluginClass(irc, module)
                irc.replySuccess()
            except ImportError:
                for callback in callbacks:
                    irc.addCallback(callback)
                irc.error('No plugin %s exists.' % name)
        else:
            irc.error('There was no callback %s.' % name)

    def unload(self, irc, msg, args):
        """<plugin>

        Unloads the callback by name; use the 'list' command to see a list
        of the currently loaded callbacks.
        """
        name = privmsgs.getArgs(args)
        callbacks = irc.removeCallback(name)
        if callbacks:
            for callback in callbacks:
                callback.die()
                del callback
            gc.collect()
            irc.replySuccess()
        else:
            irc.error('There was no callback %s' % name)

    def reconf(self, irc, msg, args):
        """takes no arguments

        Reloads the configuration files in conf.dataDir: conf/users.conf and
        conf/channels.conf, by default.
        """
        ircdb.users.reload()
        ircdb.channels.reload()
        irc.replySuccess()

Class = Owner

# vim:set shiftwidth=4 tabstop=8 expandtab textwidth=78:

<|endoftext|>


<commit_before>from datetime import datetime, timedelta

from changes.config import queue
from changes.constants import Status
from changes.models.build import Build

def cleanup_builds():
    """
    Look for any jobs which haven't checked in (but are listed in a pending state)
    and mark them as finished in an unknown state.
    """
    now = datetime.utcnow()
    cutoff = now - timedelta(minutes=5)

    build_list = Build.query.filter(
        Build.status != Status.finished,
        Build.date_modified < cutoff,
    )
    for build in build_list:
        queue.delay('sync_build', build_id=build.id.hex)
<commit_msg>Lower build check to 3 minutes<commit_after>from datetime import datetime, timedelta

from changes.config import queue
from changes.constants import Status
from changes.models.build import Build

def cleanup_builds():
    """
    Look for any jobs which haven't checked in (but are listed in a pending state)
    and mark them as finished in an unknown state.
    """
    now = datetime.utcnow()
    cutoff = now - timedelta(minutes=3)

    build_list = Build.query.filter(
        Build.status != Status.finished,
        Build.date_modified < cutoff,
    )
    for build in build_list:
        queue.delay('sync_build', build_id=build.id.hex)
<|endoftext|>