<commit_before>"""
Contains the class for the commands manager for a client.
"""
import importlib
import inspect
import sys
import typing
from collections import defaultdict

import curio

from curious.commands.context import Context
from curious.commands.help import help_command
from curious.commands.plugin import Plugin
from curious.commands.utils import prefix_check_factory
from curious.core import client as md_client
from curious.core.event import EventContext, event
from curious.dataclasses.message import Message

class CommandsManager(object):
    """
    A manager that handles commands for a client.

    First, you need to create the manager and attach it to a client:
    .. code-block:: python3

        # form 1, automatically register with the client
        manager = CommandsManager.with_client(bot)

        # form 2, manually register
        manager = CommandsManager(bot)
        manager.register_events()

    This is required to add the handler events to the client.

    Next, you need to register a message check handler. This is a callable that is called for
    every message to try and extract the command from a message, if it matches.
    By default, the manager provides an easy way to use a simple command prefix:
    .. code-block:: python3

        # at creation time
        manager = CommandsManager(bot, command_prefix="!")

        # or set it on the manager
        manager.command_prefix = "!"

    At this point, the command prefix will be available on the manager with either
    :attr:`.Manager.command_prefix` or :attr:`.Manager.message_check.prefix`.

    If you need more complex message checking, you can use ``message_check``:
    .. code-block:: python3

        manager = CommandsManager(bot, message_check=my_message_checker)
        # or
        manager.message_check = my_message_checker

    Finally, you can register plugins or modules containing plugins with the manager:
    .. code-block:: python3

        @bot.event("ready")
        async def load_plugins(ctx: EventContext):
            # load plugin explicitly
            await manager.load_plugin(PluginClass, arg1)
            # load plugins from a module
            await manager.load_plugins_from("my.plugin.module")

    You can also add free-standing commands that aren't bound to a plugin with
    :meth:`.CommandsManager.add_command`:
    .. code-block:: python3

        @command
        async def ping(ctx: CommandsContext):
            await ctx.channel.send(content="Pong!")

        manager.add_command(ping)

    These will then be available to the client.
    """

    def __init__(self, client: 'md_client.Client', *,
                 message_check=None, command_prefix: str = None):
        """
        :param client: The :class:`.Client` to use with this manager.
        :param message_check: The message check function for this manager.

            This should take two arguments, the client and message, and should return either None
            or a 2-item tuple:
              - The command word matched
              - The tokens after the command word
        """
        if message_check is None and command_prefix is None:
            raise ValueError("Must provide one of message_check or command_prefix")

        #: The client for this manager.
        self.client = client

        if message_check is None:
            message_check = prefix_check_factory(command_prefix)

        #: The message check function for this manager.
        self.message_check = message_check

        #: A dictionary mapping of <plugin name> -> <plugin> object.
        self.plugins = {}

        #: A dictionary of stand-alone commands, i.e. commands not associated with a plugin.
        self.commands = {}

        self._module_plugins = defaultdict(lambda: [])

    def register_events(self) -> None:
        """
        Copies the events to the client specified on this manager.
        """
        self.client.events.add_event(self.handle_message)
        self.client.events.event_hooks.append(self.event_hook)

        from curious.commands.decorators import command
        self.commands["help"] = command(name="help")(help_command)

    async def load_plugin(self, klass: typing.Type[Plugin], *args,
                          module: str = None):
        """
        Loads a plugin.
        .. note::

            The client instance will automatically be provided to the Plugin's ``__init__``.

        :param klass: The plugin class to load.
        :param args: Any args to provide to the plugin.
        :param module: The module name provided with this plugin. Only used interally.
        """
        # get the name and create the plugin object
        plugin_name = getattr(klass, "name", klass.__name__)
        instance = klass(self.client, *args)

        # call load, of course
        await instance.load()

        self.plugins[plugin_name] = instance
        if module is not None:
            self._module_plugins[module].append(instance)

        return instance

    async def unload_plugin(self, klass: typing.Union[Plugin, str]):
        """
        Unloads a plugin.

        :param klass: The plugin class or name of plugin to unload.
        """
        p = None
        if isinstance(klass, str):
            p = self.plugins.pop(klass)

        for k, p in self.plugins.copy().items():
            if type(p) == klass:
                p = self.plugins.pop(k)
                break

        if p is not None:
            await p.unload()

        return p

    def _lookup_command(self, name: str):
        """
        Does a lookup in plugin and standalone commands.
        """
        if name in self.commands:
            return self.commands[name]

        for plugin in self.plugins.values():
            cmds = plugin._get_commands()

            try:
                return next(filter(lambda cmd: not cmd.cmd_subcommand and
                                   (cmd.cmd_name == name or name in cmd.cmd_aliases), cmds))
            except StopIteration:
                continue

    def get_command(self, command_name: str):
        """
        Gets a command from the internal command storage.
        If provided a string separated by spaces, a subcommand lookup will be attempted.

        :param command_name: The name of the command to lookup.
        """
        # do an immediate lookup for the first token
        sp = command_name.split(" ")
        command = self._lookup_command(sp[0])

        if command is None:
            return None

        for token in sp[1:]:
            try:
                filtered = filter(lambda cmd: cmd.cmd_name == token or token in cmd.cmd_aliases,
                                  command.cmd_subcommands)
                command = next(filtered)
            except StopIteration:
                return None

        return command

    async def add_command(self, command):
        """
        Adds a command.

        :param command: A command function.
        """
        if not hasattr(command, "is_cmd"):
            raise ValueError("Commands must be decorated with the command decorator")

        self.commands[command.cmd_name] = command
        return command

    async def remove_command(self, command):
        """
        Removes a command.

        :param command: The name of the command, or the command function.
        """
        if isinstance(command, str):
            return self.commands.pop(command)
        else:
            for k, p in self.commands.copy().items():
                if p == command:
                    return self.commands.pop(k)

    async def load_plugins_from(self, import_path: str):
        """
        Loads plugins from the specified module.

        :param import_path: The import path to import.
        """
        mod = importlib.import_module(import_path)

        # define the predicate for the body scanner
        def predicate(item):
            # only accept plugin subclasses
            if not issubclass(item, Plugin):
                return False

            # ensure item is not actually Plugin
            if item == Plugin:
                return False

            # it is a plugin
            return True

        for plugin_name, plugin_class in inspect.getmembers(mod, predicate=predicate):
            await self.load_plugin(plugin_class, module=mod)

    async def unload_plugins_from(self, import_path: str):
        """
        Unloads plugins from the specified module.
        This will delete the module from sys.path.

        :param import_path: The import path.
        """
        for plugin in self._module_plugins[import_path]:
            await plugin.unload()
            self.plugins.pop(getattr(plugin, "name", "__name__"))

        del sys.modules[import_path]
        del self._module_plugins[import_path]

    async def event_hook(self, ctx: EventContext, *args, **kwargs):
        """
        The event hook for the commands manager.
        """
        taskgroup = curio.TaskGroup()
        for plugin in self.plugins.values():
            body = inspect.getmembers(plugin, predicate=lambda v: hasattr(v, "is_event"))
            for _, handler in body:
                if ctx.event_name not in handler.events:
                    continue

                await taskgroup.spawn(self.client.events._safety_wrapper(
                    handler, ctx, *args, **kwargs
                ))

        await taskgroup.join()

    async def handle_commands(self, ctx: EventContext, message: Message):
        """
        Handles commands for a message.
        """
        # step 1, match the messages
        matched = self.message_check(self.client, message)
        if inspect.isawaitable(matched):
            matched = await matched

        if matched is None:
            return None

        # deconstruct the tuple returned into more useful variables than a single tuple
        command_word, tokens = matched

        # step 2, create the new commands context
        ctx = Context(event_context=ctx, message=message)
        ctx.command_name = command_word
        ctx.tokens = tokens
        ctx.manager = self

        # step 3, invoke the context to try and match the command and run it
        await ctx.try_invoke()

    @event("message_create")
    async def handle_message(self, ctx: EventContext, message: Message):
        """
        Registered as the event handler in a client for handling commands.
        """
        return await self.handle_commands(ctx, message)
<commit_msg>Actually add `with_client` method.<commit_after>"""
Contains the class for the commands manager for a client.
"""
import importlib
import inspect
import sys
import typing
from collections import defaultdict

import curio

from curious.commands.context import Context
from curious.commands.help import help_command
from curious.commands.plugin import Plugin
from curious.commands.utils import prefix_check_factory
from curious.core import client as md_client
from curious.core.event import EventContext, event
from curious.dataclasses.message import Message

class CommandsManager(object):
    """
    A manager that handles commands for a client.

    First, you need to create the manager and attach it to a client:
    .. code-block:: python3

        # form 1, automatically register with the client
        manager = CommandsManager.with_client(bot)

        # form 2, manually register
        manager = CommandsManager(bot)
        manager.register_events()

    This is required to add the handler events to the client.

    Next, you need to register a message check handler. This is a callable that is called for
    every message to try and extract the command from a message, if it matches.
    By default, the manager provides an easy way to use a simple command prefix:
    .. code-block:: python3

        # at creation time
        manager = CommandsManager(bot, command_prefix="!")

        # or set it on the manager
        manager.command_prefix = "!"

    At this point, the command prefix will be available on the manager with either
    :attr:`.Manager.command_prefix` or :attr:`.Manager.message_check.prefix`.

    If you need more complex message checking, you can use ``message_check``:
    .. code-block:: python3

        manager = CommandsManager(bot, message_check=my_message_checker)
        # or
        manager.message_check = my_message_checker

    Finally, you can register plugins or modules containing plugins with the manager:
    .. code-block:: python3

        @bot.event("ready")
        async def load_plugins(ctx: EventContext):
            # load plugin explicitly
            await manager.load_plugin(PluginClass, arg1)
            # load plugins from a module
            await manager.load_plugins_from("my.plugin.module")

    You can also add free-standing commands that aren't bound to a plugin with
    :meth:`.CommandsManager.add_command`:
    .. code-block:: python3

        @command
        async def ping(ctx: CommandsContext):
            await ctx.channel.send(content="Pong!")

        manager.add_command(ping)

    These will then be available to the client.
    """

    def __init__(self, client: 'md_client.Client', *,
                 message_check=None, command_prefix: str = None):
        """
        :param client: The :class:`.Client` to use with this manager.
        :param message_check: The message check function for this manager.

            This should take two arguments, the client and message, and should return either None
            or a 2-item tuple:
              - The command word matched
              - The tokens after the command word
        """
        if message_check is None and command_prefix is None:
            raise ValueError("Must provide one of message_check or command_prefix")

        #: The client for this manager.
        self.client = client

        if message_check is None:
            message_check = prefix_check_factory(command_prefix)

        #: The message check function for this manager.
        self.message_check = message_check

        #: A dictionary mapping of <plugin name> -> <plugin> object.
        self.plugins = {}

        #: A dictionary of stand-alone commands, i.e. commands not associated with a plugin.
        self.commands = {}

        self._module_plugins = defaultdict(lambda: [])

    @classmethod
    def with_client(cls, client: 'md_client.Client', **kwargs):
        """
        Creates a manager and automatically registers events.
        """
        obb = cls(client=client, **kwargs)
        obb.register_events()
        return obb

    def register_events(self) -> None:
        """
        Copies the events to the client specified on this manager.
        """
        self.client.events.add_event(self.handle_message)
        self.client.events.event_hooks.append(self.event_hook)

        from curious.commands.decorators import command
        self.commands["help"] = command(name="help")(help_command)

    async def load_plugin(self, klass: typing.Type[Plugin], *args,
                          module: str = None):
        """
        Loads a plugin.
        .. note::

            The client instance will automatically be provided to the Plugin's ``__init__``.

        :param klass: The plugin class to load.
        :param args: Any args to provide to the plugin.
        :param module: The module name provided with this plugin. Only used interally.
        """
        # get the name and create the plugin object
        plugin_name = getattr(klass, "name", klass.__name__)
        instance = klass(self.client, *args)

        # call load, of course
        await instance.load()

        self.plugins[plugin_name] = instance
        if module is not None:
            self._module_plugins[module].append(instance)

        return instance

    async def unload_plugin(self, klass: typing.Union[Plugin, str]):
        """
        Unloads a plugin.

        :param klass: The plugin class or name of plugin to unload.
        """
        p = None
        if isinstance(klass, str):
            p = self.plugins.pop(klass)

        for k, p in self.plugins.copy().items():
            if type(p) == klass:
                p = self.plugins.pop(k)
                break

        if p is not None:
            await p.unload()

        return p

    def _lookup_command(self, name: str):
        """
        Does a lookup in plugin and standalone commands.
        """
        if name in self.commands:
            return self.commands[name]

        for plugin in self.plugins.values():
            cmds = plugin._get_commands()

            try:
                return next(filter(lambda cmd: not cmd.cmd_subcommand and
                                   (cmd.cmd_name == name or name in cmd.cmd_aliases), cmds))
            except StopIteration:
                continue

    def get_command(self, command_name: str):
        """
        Gets a command from the internal command storage.
        If provided a string separated by spaces, a subcommand lookup will be attempted.

        :param command_name: The name of the command to lookup.
        """
        # do an immediate lookup for the first token
        sp = command_name.split(" ")
        command = self._lookup_command(sp[0])

        if command is None:
            return None

        for token in sp[1:]:
            try:
                filtered = filter(lambda cmd: cmd.cmd_name == token or token in cmd.cmd_aliases,
                                  command.cmd_subcommands)
                command = next(filtered)
            except StopIteration:
                return None

        return command

    async def add_command(self, command):
        """
        Adds a command.

        :param command: A command function.
        """
        if not hasattr(command, "is_cmd"):
            raise ValueError("Commands must be decorated with the command decorator")

        self.commands[command.cmd_name] = command
        return command

    async def remove_command(self, command):
        """
        Removes a command.

        :param command: The name of the command, or the command function.
        """
        if isinstance(command, str):
            return self.commands.pop(command)
        else:
            for k, p in self.commands.copy().items():
                if p == command:
                    return self.commands.pop(k)

    async def load_plugins_from(self, import_path: str):
        """
        Loads plugins from the specified module.

        :param import_path: The import path to import.
        """
        mod = importlib.import_module(import_path)

        # define the predicate for the body scanner
        def predicate(item):
            # only accept plugin subclasses
            if not issubclass(item, Plugin):
                return False

            # ensure item is not actually Plugin
            if item == Plugin:
                return False

            # it is a plugin
            return True

        for plugin_name, plugin_class in inspect.getmembers(mod, predicate=predicate):
            await self.load_plugin(plugin_class, module=mod)

    async def unload_plugins_from(self, import_path: str):
        """
        Unloads plugins from the specified module.
        This will delete the module from sys.path.

        :param import_path: The import path.
        """
        for plugin in self._module_plugins[import_path]:
            await plugin.unload()
            self.plugins.pop(getattr(plugin, "name", "__name__"))

        del sys.modules[import_path]
        del self._module_plugins[import_path]

    async def event_hook(self, ctx: EventContext, *args, **kwargs):
        """
        The event hook for the commands manager.
        """
        taskgroup = curio.TaskGroup()
        for plugin in self.plugins.values():
            body = inspect.getmembers(plugin, predicate=lambda v: hasattr(v, "is_event"))
            for _, handler in body:
                if ctx.event_name not in handler.events:
                    continue

                await taskgroup.spawn(self.client.events._safety_wrapper(
                    handler, ctx, *args, **kwargs
                ))

        await taskgroup.join()

    async def handle_commands(self, ctx: EventContext, message: Message):
        """
        Handles commands for a message.
        """
        # step 1, match the messages
        matched = self.message_check(self.client, message)
        if inspect.isawaitable(matched):
            matched = await matched

        if matched is None:
            return None

        # deconstruct the tuple returned into more useful variables than a single tuple
        command_word, tokens = matched

        # step 2, create the new commands context
        ctx = Context(event_context=ctx, message=message)
        ctx.command_name = command_word
        ctx.tokens = tokens
        ctx.manager = self

        # step 3, invoke the context to try and match the command and run it
        await ctx.try_invoke()

    @event("message_create")
    async def handle_message(self, ctx: EventContext, message: Message):
        """
        Registered as the event handler in a client for handling commands.
        """
        return await self.handle_commands(ctx, message)
<|endoftext|>


<commit_before>import pcl
import numpy as np
import sensor_msgs.point_cloud2 as pcl2
import std_msgs
import rospy

def pcd_to_np(pcd_filename):
    """
    Read in PCD then return nx3 numpy array

    :type pcd_filename: str
    :rtype numpy.ndarray
    """

    pcd = pcl.load(pcd_filename)
    return pcl_to_np(pcd)

def pcl_to_np(pointcloud):
    """
    Convert PCL pointcloud to numpy nx3 numpy array

    :type pointcloud: pcl.PointCloud
    :rtype numpy.ndarray
    """

    pc_nx3 = pointcloud.to_array()
    return pc_nx3

def np_to_pcl(pc_np):
    """
    Convert nx3 numpy array to PCL pointcloud

    :type pc_np: numpy.ndarray
    :rtype pcl.PointCloud
    """

    new_pcd = pcl.PointCloud(np.array(pc_np, np.float32))
    return new_pcd

def cloud_msg_to_np(msg):
    """
    Take a ros pointclud message and convert it to
    an nx3 numpy ndarray.

    :type msg: sensor_msg.msg.PointCloud2
    :rtype numpy.ndarray
    """

    num_pts = msg.width*msg.height
    out = np.zeros((num_pts, 3))
    count = 0
    for point in pcl2.read_points(msg, skip_nans=True):
        out[count] = point
        count += 1

    # if there were nans, we need to resize cloud to skip them.
    out = out[:count]
    return out

def np_to_cloud_msg(pc_np, frame_id):
    """
    :type pc_np: numpy.ndarray
    :param pc_np: A nx3 pointcloud
    :rtype sensor_msg.msg.PointCloud2
    """

    header = std_msgs.msg.Header()
    header.stamp = rospy.Time.now()
    header.frame_id = frame_id
    cloud_msg = pcl2.create_cloud_xyz32(header, pc_np)

    return cloud_msg

def transform_cloud(pc, transform):
    """
    :type pc: numpy.ndarray
    :type transform: numpy.ndarray
    :param transform: A 4x4 homogenous transform to apply to the cloud
    :param pc: A nx3 pointcloud
    :rtype numpy.ndarray
    """

    if len(pc.shape) != 2:
        print("Warning, pc shape length should be 2")
    if pc.shape[1] != 3:
        print("Warning: pc.shape[1] != 3 your pointcloud may be transposed!!!")

    num_pts = pc.shape[0]
    homogenous_coords = np.ones((num_pts, 4))
    homogenous_coords[:, 0:3] = pc

    #need points to be 4xn
    homogenous_coords = homogenous_coords.T

    out_4xn = np.dot(transform, homogenous_coords)

    out_nx3 = out_4xn.T[:, 0:3]

    return out_nx3

<commit_msg>fixing msg to numpy<commit_after>import pcl
import numpy as np
import sensor_msgs.point_cloud2 as pcl2
import std_msgs
import rospy

def pcd_to_np(pcd_filename):
    """
    Read in PCD then return nx3 numpy array

    :type pcd_filename: str
    :rtype numpy.ndarray
    """

    pcd = pcl.load(pcd_filename)
    return pcl_to_np(pcd)

def pcl_to_np(pointcloud):
    """
    Convert PCL pointcloud to numpy nx3 numpy array

    :type pointcloud: pcl.PointCloud
    :rtype numpy.ndarray
    """

    pc_nx3 = pointcloud.to_array()
    return pc_nx3

def np_to_pcl(pc_np):
    """
    Convert nx3 numpy array to PCL pointcloud

    :type pc_np: numpy.ndarray
    :rtype pcl.PointCloud
    """

    new_pcd = pcl.PointCloud(np.array(pc_np, np.float32))
    return new_pcd

def cloud_msg_to_np(msg):
    """
    Take a ros pointclud message and convert it to
    an nx3 numpy ndarray.

    :type msg: sensor_msg.msg.PointCloud2
    :rtype numpy.ndarray
    """

    num_pts = msg.width*msg.height
    out = np.zeros((num_pts, 4))
    count = 0
    for point in pcl2.read_points(msg, skip_nans=True):
        out[count] = point
        count += 1

    # if there were nans, we need to resize cloud to skip them.
    out = out[:count, 0:3]
    return out

def np_to_cloud_msg(pc_np, frame_id):
    """
    :type pc_np: numpy.ndarray
    :param pc_np: A nx3 pointcloud
    :rtype sensor_msg.msg.PointCloud2
    """

    header = std_msgs.msg.Header()
    header.stamp = rospy.Time.now()
    header.frame_id = frame_id
    cloud_msg = pcl2.create_cloud_xyz32(header, pc_np)

    return cloud_msg

def transform_cloud(pc, transform):
    """
    :type pc: numpy.ndarray
    :type transform: numpy.ndarray
    :param transform: A 4x4 homogenous transform to apply to the cloud
    :param pc: A nx3 pointcloud
    :rtype numpy.ndarray
    """

    if len(pc.shape) != 2:
        print("Warning, pc shape length should be 2")
    if pc.shape[1] != 3:
        print("Warning: pc.shape[1] != 3 your pointcloud may be transposed!!!")

    num_pts = pc.shape[0]
    homogenous_coords = np.ones((num_pts, 4))
    homogenous_coords[:, 0:3] = pc

    #need points to be 4xn
    homogenous_coords = homogenous_coords.T

    out_4xn = np.dot(transform, homogenous_coords)

    out_nx3 = out_4xn.T[:, 0:3]

    return out_nx3

<|endoftext|>


<commit_before>import errno
import logging
import os

from rosdep2.main import _rosdep_main

from rosdistro import get_index, get_index_url, repository, get_distribution, DEFAULT_INDEX_URL
from rosdistro.source_repository_specification import SourceRepositorySpecification

from mock import patch
from rosdep2 import RosdepLookup, create_default_installer_context, get_default_installer
from rosdep2.rospkg_loader import DEFAULT_VIEW_KEY
from rosinstall_generator.generator import generate_rosinstall_for_repos
from vcstools import get_vcs_client

logger = logging.getLogger(__name__)

def mkdir_p(path):
    try:
        os.makedirs(path)
    except OSError as e:
        if e.errno == errno.EEXIST and os.path.isdir(path):
            pass
        else:
            raise

def symlink_force(source, link_name):
    logging.info("symlink '%s' => '%s'", source, link_name)
    try:
        os.symlink(source, link_name)
    except OSError as e:
        if e.errno == errno.EEXIST:
            logger.debug('symlink already exists: %s', link_name)
            logger.debug("replacing symlink from '%s' to '%s'", os.path.realpath(link_name), source)
            os.remove(link_name)
            os.symlink(source, link_name)
        else:
            raise e

class SourceRepositorySpecificationMock(SourceRepositorySpecification):
    def __init__(self, name, data):
        super(SourceRepositorySpecificationMock, self).__init__(name, data)
        self.patched_packages = data.get('packages', [])

def get_rosdistro():
    if 'ROS_DISTRO' in os.environ:
        distroname = os.environ['ROS_DISTRO']
    else:
        raise AssertionError('ROS_DISTRO is not defined in environment')

    index_url = get_index_url()
    index = get_index(index_url)

    if index_url == DEFAULT_INDEX_URL:
        logger.error('ROSDISTRO_INDEX_URL is set to the default (did you forget to source a workspace?)')
        exit(1)

    # load rosdistro with patched SourceRepositorySpecification class
    with patch.object(repository, 'SourceRepositorySpecification', SourceRepositorySpecificationMock):
        return get_distribution(index, distroname)

def update_folder(target_path, folder_mapping, verbose):
    # generate rosinstall file
    config = generate_rosinstall_for_repos(folder_mapping, version_tag=False, tar=False)

    for i, item in enumerate(config):
        assert len(item) == 1
        repo_type, attributes = next(iter(item.items()))

        try:
            path = attributes['local-name']
        except AttributeError as e:
            logger.warning('Repository #%d does not provide the necessary ' 'information: %s' % (i, e))
            continue
        try:
            url = attributes['uri']
            if 'version' in attributes:
                version = attributes['version']
        except AttributeError as e:
            logger.warning("Repository '%s' does not provide the necessary " 'information: %s' % (path, e))
            continue

        client = get_vcs_client(repo_type, os.path.join(target_path, path))
        if client.detect_presence():
            # TODO: backup folder and checkout the new version
            if client.get_url() != url:
                logger.error("local vcs url is different from the distro's url:\n\tlocal:  %s\n\tdistro: %s",
                             client.get_url(), url)

            # skip version because we only want to pull
            if not client.update(verbose=verbose):
                logger.error("Could not update %s repo: %s", repo_type, path)
                exit(1)
        else:
            assert client.checkout(url, version=version, verbose=verbose)

cached_view = None

def get_rosdep(key):
    installer_context = create_default_installer_context(verbose=False)

    installer, installer_keys, default_key, os_name, os_version = get_default_installer(
        installer_context=installer_context, verbose=False)

    global cached_view
    if not cached_view:
        lookup = RosdepLookup.create_from_rospkg()
        lookup.verbose = False

        view = lookup.get_rosdep_view(DEFAULT_VIEW_KEY, verbose=False)
        cached_view = view
    else:
        view = cached_view

    try:
        d = view.lookup(key)
        rule_installer, rule = d.get_rule_for_platform(os_name, os_version, installer_keys, default_key)
        return rule_installer, rule
    except KeyError:
        return False

def rosdep_install(path):
    result = _rosdep_main(['install', '--from-paths', path, '-i', '-y'])
    logger.info('rosdep exited with code %d', result)
    return result
<commit_msg>Run pip without root when installing rosdeps<commit_after>import errno
import logging
import os

from rosdep2.main import _rosdep_main

from rosdistro import get_index, get_index_url, repository, get_distribution, DEFAULT_INDEX_URL
from rosdistro.source_repository_specification import SourceRepositorySpecification

from mock import patch
from rosdep2 import RosdepLookup, create_default_installer_context, get_default_installer
from rosdep2.rospkg_loader import DEFAULT_VIEW_KEY
from rosinstall_generator.generator import generate_rosinstall_for_repos
from vcstools import get_vcs_client

logger = logging.getLogger(__name__)

def mkdir_p(path):
    try:
        os.makedirs(path)
    except OSError as e:
        if e.errno == errno.EEXIST and os.path.isdir(path):
            pass
        else:
            raise

def symlink_force(source, link_name):
    logging.info("symlink '%s' => '%s'", source, link_name)
    try:
        os.symlink(source, link_name)
    except OSError as e:
        if e.errno == errno.EEXIST:
            logger.debug('symlink already exists: %s', link_name)
            logger.debug("replacing symlink from '%s' to '%s'", os.path.realpath(link_name), source)
            os.remove(link_name)
            os.symlink(source, link_name)
        else:
            raise e

class SourceRepositorySpecificationMock(SourceRepositorySpecification):
    def __init__(self, name, data):
        super(SourceRepositorySpecificationMock, self).__init__(name, data)
        self.patched_packages = data.get('packages', [])

def get_rosdistro():
    if 'ROS_DISTRO' in os.environ:
        distroname = os.environ['ROS_DISTRO']
    else:
        raise AssertionError('ROS_DISTRO is not defined in environment')

    index_url = get_index_url()
    index = get_index(index_url)

    if index_url == DEFAULT_INDEX_URL:
        logger.error('ROSDISTRO_INDEX_URL is set to the default (did you forget to source a workspace?)')
        exit(1)

    # load rosdistro with patched SourceRepositorySpecification class
    with patch.object(repository, 'SourceRepositorySpecification', SourceRepositorySpecificationMock):
        return get_distribution(index, distroname)

def update_folder(target_path, folder_mapping, verbose):
    # generate rosinstall file
    config = generate_rosinstall_for_repos(folder_mapping, version_tag=False, tar=False)

    for i, item in enumerate(config):
        assert len(item) == 1
        repo_type, attributes = next(iter(item.items()))

        try:
            path = attributes['local-name']
        except AttributeError as e:
            logger.warning('Repository #%d does not provide the necessary ' 'information: %s' % (i, e))
            continue
        try:
            url = attributes['uri']
            if 'version' in attributes:
                version = attributes['version']
        except AttributeError as e:
            logger.warning("Repository '%s' does not provide the necessary " 'information: %s' % (path, e))
            continue

        client = get_vcs_client(repo_type, os.path.join(target_path, path))
        if client.detect_presence():
            # TODO: backup folder and checkout the new version
            if client.get_url() != url:
                logger.error("local vcs url is different from the distro's url:\n\tlocal:  %s\n\tdistro: %s",
                             client.get_url(), url)

            # skip version because we only want to pull
            if not client.update(verbose=verbose):
                logger.error("Could not update %s repo: %s", repo_type, path)
                exit(1)
        else:
            assert client.checkout(url, version=version, verbose=verbose)

cached_view = None

def get_rosdep(key):
    installer_context = create_default_installer_context(verbose=False)

    installer, installer_keys, default_key, os_name, os_version = get_default_installer(
        installer_context=installer_context, verbose=False)

    global cached_view
    if not cached_view:
        lookup = RosdepLookup.create_from_rospkg()
        lookup.verbose = False

        view = lookup.get_rosdep_view(DEFAULT_VIEW_KEY, verbose=False)
        cached_view = view
    else:
        view = cached_view

    try:
        d = view.lookup(key)
        rule_installer, rule = d.get_rule_for_platform(os_name, os_version, installer_keys, default_key)
        return rule_installer, rule
    except KeyError:
        return False

def rosdep_install(path):
    result = _rosdep_main(['install', '--from-paths', path, '-i', '-y', '--as-root', 'pip:false'])
    logger.info('rosdep exited with code %d', result)
    return result
<|endoftext|>


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

#Water meter monitor
#Written by: Miguel Leonardo
#Version: Beta1.0
#ADC 1015 SENSOR MODULE FOR ADDRESS 0x4a

import logging
from time import sleep
import os
import sys
import subprocess
import log
from ADC_driver import ADCdriver
import threading
import struct
import time, signal
from Adafruit_ADS1x15 import ADS1x15
import csv
import datetime as date

# File manipulation libraries
#------------------------------------------------------------------
from os      import remove as remove_file
from os 	 import makedirs
from shutil  import copy   as copy_file
from os.path import join   as join_filename
from os.path import exists
from os.path import dirname
import os
from xml.dom.minidom import Element
from filenamer import Filenamer
from collections import namedtuple
from array import array
#------------------------------------------------------------------
from subprocess import Popen, PIPE, STDOUT
_ntuple_diskusage = namedtuple('usage', 'total used free')

#------------------------------------------------------------------
log.setLevel(logging.DEBUG)
#log.set_udp_destination('estimated.local')
log.set_udp_destination('localhost')
#------------------------------------------------------------------

#ADC configurations
#------------------------------------------------------------------
ADS1015 = 0x00  # 12-bit ADC

# Select the gain
#__gain = 61    # +/- 6.144V
gain = 4096  # +/- 4.096V
#__gain = 2048  # +/- 2.048V
#__gain = 1024  # +/- 1.024V
#__gain = 512   # +/- 0.512V
#__gain = 256   # +/- 0.256V

# Select the sample rate
#__sps = 8    # 8 samples per second
#__sps = 16   # 16 samples per second
#__sps = 32   # 32 samples per second
#__sps = 64   # 64 samples per second
#__sps = 128  # 128 samples per second
#sps = 250  # 250 samples per second
#__sps = 475  # 475 samples per second
sps = 860  # 860 samples per second

# Select Address
#ADC0 = 0x48
#ADC1 = 0x49
ADC2 = 0x4a
#ADC3 = 0x4b
#------------------------------------------------------------------

#Site information
#------------------------------------------------------------------
Datalogger_name = "RPI_LOGGER"
Site_name = "David Rosenberg's House"
Site_description = "Port1:Not defined   -  Port2:Not defined - Port3:Not defined - Port4:Not defined"
Port1_name = "Not defined"
Conv_factor1 = 0.01
Port2_name = "Battery"
Conv_factor2 = 0.01
#0.015526316
Port3_name = "Not defined"
Conv_factor3 = 0.01
Port4_name = "WaterMeter_Rev"
Conv_factor4 = 0.01
#------------------------------------------------------------------

def signal_handler(signal, frame):
        print 'You pressed Ctrl+C!'
        sys.exit(0)
signal.signal(signal.SIGINT, signal_handler)
#print 'Press Ctrl+C to exit'

#Sensor_Module Class start here
#------------------------------------------------------------------
class SensorModule():

    def __init__(self,data_directory = '/home/pi/Datalog/',sensor_id='BUS_MEN_BATHROOM',sitename = 'WATER_METERS', enumerate_directory = True, time_support = 5):
        logging.debug(sensor_id + ' ' + sitename)

        self._ntuple_diskusage = namedtuple('usage', 'total used free')

        self._sitename = sitename

        enumerate_data_directory = enumerate_directory
        #Accessing DataLogger directory - This will create the directory if not exist
        if enumerate_data_directory:
            directorynamer = Filenamer('DataLog_%05d/')
            self.data_directory = join_filename(data_directory, directorynamer.next_filename())
            while exists(self.data_directory):
                self.data_directory = join_filename(data_directory, directorynamer.next_filename())
        else:
            self.data_directory = data_directory
        if not exists(self.data_directory):
            makedirs(self.data_directory)
            pass

        #Opening/Creating and initializing csv file in write mode
        #Initializing Datalog File
        self._output_file = open(self.data_directory + 'sensors_datalog' + '.csv', 'w')
        self._write = csv.writer(self._output_file, delimiter=',', quotechar='"', quoting=csv.QUOTE_MINIMAL)
        header1 = ["Datalogger Name:",Datalogger_name]
        header2 = ["Site Name:",Site_name]
	header3 = ["Site Descrption:",Site_description]
        header4 = ["TIMESTAMP","RECORD","MEM_SPACE_AVAILABLE","BATT_VOLT",Port1_name, Port2_name, Port3_name, Port4_name]
        self._write.writerow(header1)
        self._write.writerow(header2)
        self._write.writerow(header3)
	self._write.writerow(header4)
        self._output_file.close()

        #Starting ADC
        self._adc = ADS1x15(address=ADC2,ic=ADS1015)
        self._start = True

        #Datalogger interval settings

        self._sample_time = time_support
        self._count = 0
        self._count1 = 0
        self._pulse_count0 = 0
        self._pulse_count1 = 0
        self._pulse_count2 = 0
        self._pulse_count3 = 0
        self._threshold0 = 4.094
        self._threshold1 = 3
        self._threshold2 = 3
        self._threshold3 = 3

        self._MotionPause = 5

        self._record = 0

        self._conv_factor1 = Conv_factor1
        self._conv_factor2 = Conv_factor2
        self._conv_factor3 = Conv_factor3
        self._conv_factor4 = Conv_factor4

        self._time_support = time_support

        #Defining data buffers

        self._intarray = array('i')
        self._intarray1 = array('i')
        self._intarray2= array('i')
        self._intarray3 = array('i')

        self._reading_1 = 0
        self._reading_2 = 0
        self._reading_3 = 0
        self._reading_4 = 0

        #Go
        self._run()
        pass

    def _run(self):

        capture = True
        sample = 0
        while self._start:
            time_lapse = 0
            acquire = True
            self._startTime = time.time()

            while acquire:

                #This section reads the voltage levels on the 4 port ADCs
                #--------------------------------------------------------------------------------------------------------
                self._volts0 = self._adc.readADCSingleEnded(0, gain, sps)/1000#RAW READING - RECOMENDED FOR MOTION SENSOR
                self._volts1 = self._adc.readADCSingleEnded(1, gain, sps)/1000#LM311 READING
                self._volts2 = self._adc.readADCSingleEnded(2, gain, sps)/1000#LM311 READING
                self._volts3 = self._adc.readADCSingleEnded(3, gain, sps)/1000#LM311 READING
                #--------------------------------------------------------------------------------------------------------

                #This section converts input data into pulses
                #--------------------------------------------------------------------------------------------------------
                self._intarray.append(self._pulse_detection(self._volts0, self._threshold0))
                self._intarray1.append(self._pulse_detection(self._volts1, self._threshold1))
                self._intarray2.append(self._pulse_detection(self._volts2, self._threshold2))
                self._intarray3.append(self._pulse_detection(self._volts3, self._threshold3))
                #--------------------------------------------------------------------------------------------------------

                #This section is for specific used with a motion sensor
                #--------------------------------------------------------------------------------------------------------
                if self._volts0 < self._threshold0:
                    if capture:
                        self._pulse_count0 = self._pulse_count0 + 1
                        #logging.debug('System running... :)')
                        haltTime = time.time()
                        capture = False
                    self._halt = (time.time()-haltTime)
                    if self._halt > self._MotionPause:
                        capture = True
                #--------------------------------------------------------------------------------------------------------

                #Pulse count mode definition 1)Count X occurrences, 2)Count falling edge, 3)Count rising edge.
                #Make adjustments here, if required.
                #--------------------------------------------------------------------------------------------------------
                #self._reading_1 = self._falling_edge_count(self._intarray)
		self._reading_1 = self._pulse_count0
                self._reading_2 = self._falling_edge_count(self._intarray1)
                self._reading_3 = self._falling_edge_count(self._intarray2)
                self._reading_4 = self._falling_edge_count(self._intarray3)
                #--------------------------------------------------------------------------------------------------------

                #This section creates the wait time based on the data collection time frame defined
                self._duration = (time.time() - self._startTime)
                if self._duration > self._sample_time:
                    acquire = False
                    self._record = self._record + 1

                    #Dataloging
                    self._capture_wm(self._reading_1, self._reading_2, self._reading_3, self._reading_4, self._write)

                    #self._print_flowrate(self._reading_1, self._reading_2, self._reading_3, self._reading_4)
                    #Reinitialize buffers and variables
                    self._reset()

                #Debug
                self._print_readings(self._reading_1, self._reading_2, self._reading_3, self._reading_4)

    def _print_readings(self,reading1, reading2, reading3, reading4):

        os.system('clear')
        print 'Duration: %.3f' %self._duration
        print '---------------------'
        print 'ADC0: %.6f' %(self._volts0) + 'Count: %d' %reading1
        print 'ADC1: %.6f' %(self._volts1) + 'Count: %d' %reading2
        print 'ADC2: %.6f' %(self._volts2) + 'Count: %d' %reading3
        print 'ADC3: %.6f' %(self._volts3) + 'Count: %d' %reading4
        print '---------------------'
        print self._disk_usage("/")
        print 'Press Ctrl+C to exit'
        pass
    def _print_flowrate(self,reading1, reading2, reading3, reading4):

        os.system('clear')
        print 'Duration: %.3f' %self._duration
        print '---------------------'
        print 'ADC0: %.6f' %(self._volts0) + ' Persons: %f' %reading1 #%self._rev_to_gpm(reading1, self._conv_factor1, self._time_support) + ' GPM'
        print 'ADC1: %.6f' %(self._volts1) + ' Flowrate: %f' %self._rev_to_gpm(reading2, self._conv_factor2, self._time_support) + ' GPM %s' %Port2_name
        print 'ADC2: %.6f' %(self._volts2) + ' Flowrate: %f' %self._rev_to_gpm(reading3, self._conv_factor3, self._time_support) + ' GPM %s' %Port3_name
        print 'ADC3: %.6f' %(self._volts3) + ' Flowrate: %f' %self._rev_to_gpm(reading4, self._conv_factor4, self._time_support) + ' GPM %s' %Port4_name
        print '---------------------'
        #print self._disk_usage("/")
        print 'Press Ctrl+C to exit'
        pass
    def _rev_to_gpm(self, reading, conv_factor, time_support):

        volume = reading*conv_factor #Gallons per time support
        gpm = (volume/time_support)*60
        return gpm

    def _rev_to_volume(self, reading, conv_factor, time_support):

        volume = reading*conv_factor #Gallons
        return volume

    def _capture_wm(self, Reading1, Reading2, Reading3, Reading4, write):

        Record = self._record
        MEM_space_available = self._disk_usage("/")
        Bat_Volt = 5

        Time = time.time()
        Date_Time = date.datetime.now()
        data = [Date_Time, Record,MEM_space_available, Bat_Volt, Reading1, Reading2, Reading3, Reading4]
        self._log_data_csv(data)

        pass

    def _pulse_detection(self, reading, threshold):

        if reading > threshold:
            pulse = 1
        else:
            pulse = 0
        return pulse

    def pulse_count(self,array):
        count = array.count(1)
        return count

    def _falling_edge_count(self, array):

        count = 0
        if array.count(1) > 0:
           for elements in range(0,len(array)-1):
               previous_element = array[elements]
               next_element = array[elements+1]

               if array[elements]==1:
                  if array[elements+1]==0:
                          count = count + 1
        return count

    def _log_data_csv(self, data):

        self._output_file = open(self.data_directory + 'sensors_datalog' + '.csv', 'a')
        self._write = csv.writer(self._output_file, delimiter=',', quotechar='"', quoting=csv.QUOTE_MINIMAL)
        self._write.writerow(data)
        self._output_file.close()

        pass

    def _reset(self):

        self._pulse_count0 = 0
        self._pulse_count1 = 0
        self._pulse_count2 = 0
        self._pulse_count3 = 0
        self._intarray = array('i')
        self._intarray1 = array('i')
        self._intarray2 = array('i')
        self._intarray3 = array('i')
        pass

    def _disk_usage(self, path):
        st = os.statvfs(path)
        free = st.f_bavail * st.f_frsize
        total = st.f_blocks * st.f_frsize
        used = (st.f_blocks - st.f_bfree) * st.f_frsize
        self._ntuple_diskusage(total, used, free)
        return free

    def __del__(self):
        print 'Files Closed'
        pass

def main():

    a = SensorModule()

    pass

main()

<commit_msg>Modified sensor module<commit_after>#!/usr/bin/env python

#Water meter monitor
#Written by: Miguel Leonardo
#Version: Beta1.0
#ADC 1015 SENSOR MODULE FOR ADDRESS 0x4a

import logging
from time import sleep
import os
import sys
import subprocess
import log
from ADC_driver import ADCdriver
import threading
import struct
import time, signal
from Adafruit_ADS1x15 import ADS1x15
import csv
import datetime as date

# File manipulation libraries
#------------------------------------------------------------------
from os      import remove as remove_file
from os 	 import makedirs
from shutil  import copy   as copy_file
from os.path import join   as join_filename
from os.path import exists
from os.path import dirname
import os
from xml.dom.minidom import Element
from filenamer import Filenamer
from collections import namedtuple
from array import array
#------------------------------------------------------------------
from subprocess import Popen, PIPE, STDOUT
_ntuple_diskusage = namedtuple('usage', 'total used free')

#------------------------------------------------------------------
log.setLevel(logging.DEBUG)
#log.set_udp_destination('estimated.local')
log.set_udp_destination('localhost')
#------------------------------------------------------------------

#ADC configurations
#------------------------------------------------------------------
ADS1015 = 0x00  # 12-bit ADC

# Select the gain
#__gain = 61    # +/- 6.144V
gain = 4096  # +/- 4.096V
#__gain = 2048  # +/- 2.048V
#__gain = 1024  # +/- 1.024V
#__gain = 512   # +/- 0.512V
#__gain = 256   # +/- 0.256V

# Select the sample rate
#__sps = 8    # 8 samples per second
#__sps = 16   # 16 samples per second
#__sps = 32   # 32 samples per second
#__sps = 64   # 64 samples per second
#__sps = 128  # 128 samples per second
#sps = 250  # 250 samples per second
#__sps = 475  # 475 samples per second
sps = 860  # 860 samples per second

# Select Address
#ADC0 = 0x48
#ADC1 = 0x49
ADC2 = 0x4a
#ADC3 = 0x4b
#------------------------------------------------------------------

#Site information
#------------------------------------------------------------------
Datalogger_name = "RPI_LOGGER"
Site_name = "David Rosenberg's House"
Site_description = "Port1:Not defined   -  Port2:Not defined - Port3:Not defined - Port4:Not defined"
Port1_name = "Not defined"
Conv_factor1 = 0.01
Port2_name = "Battery"
Conv_factor2 = 0.01
#0.015526316
Port3_name = "Not defined"
Conv_factor3 = 0.01
Port4_name = "WaterMeter_Rev"
Conv_factor4 = 0.01
#------------------------------------------------------------------

def signal_handler(signal, frame):
        print 'You pressed Ctrl+C!'
        sys.exit(0)
signal.signal(signal.SIGINT, signal_handler)
#print 'Press Ctrl+C to exit'

#Sensor_Module Class start here
#------------------------------------------------------------------
class SensorModule():

    def __init__(self,data_directory = '/home/pi/Datalog/',sensor_id='BUS_MEN_BATHROOM',sitename = 'WATER_METERS', enumerate_directory = True, time_support = 5):
        logging.debug(sensor_id + ' ' + sitename)

        self._ntuple_diskusage = namedtuple('usage', 'total used free')

        self._sitename = sitename

        enumerate_data_directory = enumerate_directory
        #Accessing DataLogger directory - This will create the directory if not exist
        if enumerate_data_directory:
            directorynamer = Filenamer('DataLog_%05d/')
            self.data_directory = join_filename(data_directory, directorynamer.next_filename())
            while exists(self.data_directory):
                self.data_directory = join_filename(data_directory, directorynamer.next_filename())
        else:
            self.data_directory = data_directory
        if not exists(self.data_directory):
            makedirs(self.data_directory)
            pass

        #Opening/Creating and initializing csv file in write mode
        #Initializing Datalog File
        self._output_file = open(self.data_directory + 'sensors_datalog' + '.csv', 'w')
        self._write = csv.writer(self._output_file, delimiter=',', quotechar='"', quoting=csv.QUOTE_MINIMAL)
        header1 = ["Datalogger Name:",Datalogger_name]
        header2 = ["Site Name:",Site_name]
	header3 = ["Site Descrption:",Site_description]
        #header4 = ["TIMESTAMP","RECORD","MEM_SPACE_AVAILABLE","BATT_VOLT",Port1_name, Port2_name, Port3_name, Port4_name]
        header4 = ["TIMESTAMP","RECORD","MEM_SPACE_AVAILABLE","BATT_VOLT",Port4_name]
        self._write.writerow(header1)
        self._write.writerow(header2)
        self._write.writerow(header3)
	self._write.writerow(header4)
        self._output_file.close()

        #Starting ADC
        self._adc = ADS1x15(address=ADC2,ic=ADS1015)
        self._start = True

        #Datalogger interval settings

        self._sample_time = time_support
        self._count = 0
        self._count1 = 0
        self._pulse_count0 = 0
        self._pulse_count1 = 0
        self._pulse_count2 = 0
        self._pulse_count3 = 0
        self._threshold0 = 4.094
        self._threshold1 = 3
        self._threshold2 = 3
        self._threshold3 = 3

        self._MotionPause = 5

        self._record = 0

        self._conv_factor1 = Conv_factor1
        self._conv_factor2 = Conv_factor2
        self._conv_factor3 = Conv_factor3
        self._conv_factor4 = Conv_factor4

        self._time_support = time_support

        #Defining data buffers

        self._intarray = array('i')
        self._intarray1 = array('i')
        self._intarray2= array('i')
        self._intarray3 = array('i')

        self._reading_1 = 0
        self._reading_2 = 0
        self._reading_3 = 0
        self._reading_4 = 0

        #Go
        self._run()
        pass

    def _run(self):

        capture = True
        sample = 0
        while self._start:
            time_lapse = 0
            acquire = True
            self._startTime = time.time()

            while acquire:

                #This section reads the voltage levels on the 4 port ADCs
                #--------------------------------------------------------------------------------------------------------
                self._volts0 = self._adc.readADCSingleEnded(0, gain, sps)/1000#RAW READING - RECOMENDED FOR MOTION SENSOR
                self._volts1 = self._adc.readADCSingleEnded(1, gain, sps)/1000#LM311 READING
                self._volts2 = self._adc.readADCSingleEnded(2, gain, sps)/1000#LM311 READING
                self._volts3 = self._adc.readADCSingleEnded(3, gain, sps)/1000#LM311 READING
                #--------------------------------------------------------------------------------------------------------

                #This section converts input data into pulses
                #--------------------------------------------------------------------------------------------------------
                self._intarray.append(self._pulse_detection(self._volts0, self._threshold0))
                self._intarray1.append(self._pulse_detection(self._volts1, self._threshold1))
                self._intarray2.append(self._pulse_detection(self._volts2, self._threshold2))
                self._intarray3.append(self._pulse_detection(self._volts3, self._threshold3))
                #--------------------------------------------------------------------------------------------------------

                #This section is for specific used with a motion sensor
                #--------------------------------------------------------------------------------------------------------
                if self._volts0 < self._threshold0:
                    if capture:
                        self._pulse_count0 = self._pulse_count0 + 1
                        #logging.debug('System running... :)')
                        haltTime = time.time()
                        capture = False
                    self._halt = (time.time()-haltTime)
                    if self._halt > self._MotionPause:
                        capture = True
                #--------------------------------------------------------------------------------------------------------

                #Pulse count mode definition 1)Count X occurrences, 2)Count falling edge, 3)Count rising edge.
                #Make adjustments here, if required.
                #--------------------------------------------------------------------------------------------------------
                #self._reading_1 = self._falling_edge_count(self._intarray)
		self._reading_1 = self._pulse_count0
                self._reading_2 = self._falling_edge_count(self._intarray1)
                self._reading_3 = self._falling_edge_count(self._intarray2)
                self._reading_4 = self._falling_edge_count(self._intarray3)
                #--------------------------------------------------------------------------------------------------------

                #This section creates the wait time based on the data collection time frame defined
                self._duration = (time.time() - self._startTime)
                if self._duration > self._sample_time:
                    acquire = False
                    self._record = self._record + 1

                    #Dataloging
                    self._capture_wm(self._reading_1, self._reading_2, self._reading_3, self._reading_4, self._write)

                    self._print_flowrate(self._reading_1, self._reading_2, self._reading_3, self._reading_4)
                    #Reinitialize buffers and variables
                    self._reset()

                #Debug
                #self._print_readings(self._reading_1, self._reading_2, self._reading_3, self._reading_4)

    def _print_readings(self,reading1, reading2, reading3, reading4):

        os.system('clear')
        print 'Duration: %.3f' %self._duration
        print '---------------------'
        print 'ADC0: %.6f' %(self._volts0) + 'Count: %d' %reading1
        print 'ADC1: %.6f' %(self._volts1) + 'Count: %d' %reading2
        print 'ADC2: %.6f' %(self._volts2) + 'Count: %d' %reading3
        print 'ADC3: %.6f' %(self._volts3) + 'Count: %d' %reading4
        print '---------------------'
        print self._disk_usage("/")
        print 'Press Ctrl+C to exit'
        pass
    def _print_flowrate(self,reading1, reading2, reading3, reading4):

        os.system('clear')
        print 'Duration: %.3f' %self._duration
        print '---------------------'
        #print 'ADC0: %.6f' %(self._volts0) + ' Persons: %f' %reading1 #%self._rev_to_gpm(reading1, self._conv_factor1, self._time_support) + ' GPM'
        #print 'ADC1: %.6f' %(self._volts1) + ' Flowrate: %f' %self._rev_to_gpm(reading2, self._conv_factor2, self._time_support) + ' GPM %s' %Port2_name
        #print 'ADC2: %.6f' %(self._volts2) + ' Flowrate: %f' %self._rev_to_gpm(reading3, self._conv_factor3, self._time_support) + ' GPM %s' %Port3_name
        print 'ADC3: %.6f' %(self._volts3) + ' Flowrate: %f' %self._rev_to_gpm(reading4, self._conv_factor4, self._time_support) + ' GPM %s' %Port4_name
        print '---------------------'
        #print self._disk_usage("/")
        print 'Press Ctrl+C to exit'
        pass
    def _rev_to_gpm(self, reading, conv_factor, time_support):

        volume = reading*conv_factor #Gallons per time support
        gpm = (volume/time_support)*60
        return gpm

    def _rev_to_volume(self, reading, conv_factor, time_support):

        volume = reading*conv_factor #Gallons
        return volume

    def _capture_wm(self, Reading1, Reading2, Reading3, Reading4, write):

        Record = self._record
        MEM_space_available = self._disk_usage("/")
        Bat_Volt = Reading2

        Time = time.time()
        Date_Time = date.datetime.now()
        #data = [Date_Time, Record,MEM_space_available, Bat_Volt, Reading1, Reading2, Reading3, Reading4]
        data = [Date_Time, Record,MEM_space_available, Bat_Volt, Reading4]
        self._log_data_csv(data)

        pass

    def _pulse_detection(self, reading, threshold):

        if reading > threshold:
            pulse = 1
        else:
            pulse = 0
        return pulse

    def pulse_count(self,array):
        count = array.count(1)
        return count

    def _falling_edge_count(self, array):

        count = 0
        if array.count(1) > 0:
           for elements in range(0,len(array)-1):
               previous_element = array[elements]
               next_element = array[elements+1]

               if array[elements]==1:
                  if array[elements+1]==0:
                          count = count + 1
        return count

    def _log_data_csv(self, data):

        self._output_file = open(self.data_directory + 'sensors_datalog' + '.csv', 'a')
        self._write = csv.writer(self._output_file, delimiter=',', quotechar='"', quoting=csv.QUOTE_MINIMAL)
        self._write.writerow(data)
        self._output_file.close()

        pass

    def _reset(self):

        self._pulse_count0 = 0
        self._pulse_count1 = 0
        self._pulse_count2 = 0
        self._pulse_count3 = 0
        self._intarray = array('i')
        self._intarray1 = array('i')
        self._intarray2 = array('i')
        self._intarray3 = array('i')
        pass

    def _disk_usage(self, path):
        st = os.statvfs(path)
        free = st.f_bavail * st.f_frsize
        total = st.f_blocks * st.f_frsize
        used = (st.f_blocks - st.f_bfree) * st.f_frsize
        self._ntuple_diskusage(total, used, free)
        return free

    def __del__(self):
        print 'Files Closed'
        pass

def main():

    a = SensorModule()

    pass

main()

<|endoftext|>


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

import argparse

# prog = sys.argv[0], you could change if you want, prog="myprogram"
parser = argparse.ArgumentParser(description='Concatenate FILE(s), or standard input, to standard output.',
                                 version="%(prog)s 8.20",
                                 usage="cat [OPTION]... [FILE]...",
                                 epilog="""With no FILE, or when FILE is -, read standard input.\n
Examples:
  cat f - g  Output f's contents, then standard input, then g's contents.
  cat        Copy standard input to standard output.

Report cat bugs to bug-coreutils@gnu.org
GNU coreutils home page: <http://www.gnu.org/software/coreutils/>
General help using GNU software: <http://www.gnu.org/gethelp/>
For complete documentation, run: info coreutils 'cat invocation'""")

parser.parse_args()<commit_msg>Introduce argument<commit_after>#!/usr/bin/env python

import argparse

# prog = sys.argv[0], you could change if you want, prog="myprogram"
parser = argparse.ArgumentParser(description='Concatenate FILE(s), or standard input, to standard output.',
                                 version="%(prog)s 8.20",
                                 usage="cat [OPTION]... [FILE]...",
                                 epilog="""With no FILE, or when FILE is -, read standard input.\n
Examples:
  cat f - g  Output f's contents, then standard input, then g's contents.
  cat        Copy standard input to standard output.

Report cat bugs to bug-coreutils@gnu.org
GNU coreutils home page: <http://www.gnu.org/software/coreutils/>
General help using GNU software: <http://www.gnu.org/gethelp/>
For complete documentation, run: info coreutils 'cat invocation'""")

parser.add_argument("-A", "--show-all",
                    help="equivalent to -vET",
                    action="store_true")
parser.add_argument("-b", "--number-nonblank",
                    help="number nonempty output lines, overrides -n",
                    action="store_true")
parser.add_argument("-e",
                    help="equivalent to -vE",
                    action="store_true")

parser.parse_args()<|endoftext|>


<commit_before>"""Monkey-patching to make coverage work right in some cases."""

import multiprocessing
import multiprocessing.process
import sys

# An attribute that will be set on modules to indicate that they have been
# monkey-patched.
MARKER = "_coverage$patched"

def patch_multiprocessing():
    """Monkey-patch the multiprocessing module.

    This enables coverage measurement of processes started by multiprocessing.
    This is wildly experimental!

    """
    if hasattr(multiprocessing, MARKER):
        return

    if sys.version_info >= (3, 4):
        klass = multiprocessing.process.BaseProcess
    else:
        klass = multiprocessing.Process

    original_bootstrap = klass._bootstrap

    class ProcessWithCoverage(klass):
        """A replacement for multiprocess.Process that starts coverage."""
        def _bootstrap(self):
            from coverage import Coverage
            cov = Coverage(data_suffix=True)
            cov.start()
            try:
                return original_bootstrap(self)
            finally:
                cov.stop()
                cov.save()

    if sys.version_info >= (3, 4):
        klass._bootstrap = ProcessWithCoverage._bootstrap
    else:
        multiprocessing.Process = ProcessWithCoverage

    setattr(multiprocessing, MARKER, True)
<commit_msg>A little cleanup of multiprocessing monkeypatching<commit_after>"""Monkey-patching to make coverage work right in some cases."""

import multiprocessing
import multiprocessing.process
import sys

# An attribute that will be set on modules to indicate that they have been
# monkey-patched.
PATCHED_MARKER = "_coverage$patched"

def patch_multiprocessing():
    """Monkey-patch the multiprocessing module.

    This enables coverage measurement of processes started by multiprocessing.
    This is wildly experimental!

    """
    if hasattr(multiprocessing, PATCHED_MARKER):
        return

    if sys.version_info >= (3, 4):
        klass = multiprocessing.process.BaseProcess
    else:
        klass = multiprocessing.Process

    original_bootstrap = klass._bootstrap

    class ProcessWithCoverage(klass):
        """A replacement for multiprocess.Process that starts coverage."""
        def _bootstrap(self):
            """Wrapper around _bootstrap to start coverage."""
            from coverage import Coverage
            cov = Coverage(data_suffix=True)
            cov.start()
            try:
                return original_bootstrap(self)
            finally:
                cov.stop()
                cov.save()

    if sys.version_info >= (3, 4):
        klass._bootstrap = ProcessWithCoverage._bootstrap
    else:
        multiprocessing.Process = ProcessWithCoverage

    setattr(multiprocessing, PATCHED_MARKER, True)
<|endoftext|>


<commit_before>import logging
from .logger import CPNestLogger
from .cpnest import CPNest

logging.setLoggerClass(CPNestLogger)

__version__ = '0.9.10'

__all__ = ['model',
           'NestedSampling',
           'parameter',
           'sampler',
           'cpnest',
           'nest2pos',
           'proposal',
           'plot',
           'logger']

<commit_msg>Get version number in module from distribution<commit_after>import logging
from .logger import CPNestLogger
from .cpnest import CPNest

# Get the version number from git tag
from pkg_resources import get_distribution, DistributionNotFound
try:
    __version__ = get_distribution(__name__).version
except DistributionNotFound:
    # package is not installed
    __version__ = "dev"

logging.setLoggerClass(CPNestLogger)

__all__ = ['model',
           'NestedSampling',
           'parameter',
           'sampler',
           'cpnest',
           'nest2pos',
           'proposal',
           'plot',
           'logger']

<|endoftext|>


<commit_before>"""FlatDict is a dict object that allows for single level, delimited
key/value pair mapping of nested dictionaries.

"""
import collections

__version__ = '3.2.1'

NO_DEFAULT = object()

# Python 2/3 string compat
try:
    basestring
except NameError:
    basestring = str

class FlatDict(collections.MutableMapping):
    """:class:`~flatdict.FlatDict` is a dictionary object that allows for
    single level, delimited key/value pair mapping of nested dictionaries.
    The default delimiter value is ``:`` but can be changed in the constructor
    or by calling :meth:`FlatDict.set_delimiter`.

    """
    _COERCE = dict

    def __init__(self, value=None, delimiter=':'):
        super(FlatDict, self).__init__()
        self._values = {}
        self._delimiter = delimiter
        self.update(value)

    def __contains__(self, key):
        """Check to see if the key exists, checking for both delimited and
        not delimited key values.

        :param mixed key: The key to check for

        """
        if self._has_delimiter(key):
            pk, ck = key.split(self._delimiter, 1)
            return pk in self._values and ck in self._values[pk]
        return key in self._values

    def __delitem__(self, key):
        """Delete the item for the specified key, automatically dealing with
        nested children.

        :param mixed key: The key to use
        :raises: KeyError

        """
        if key not in self:
            raise KeyError
        if self._has_delimiter(key):
            pk, ck = key.split(self._delimiter, 1)
            del self._values[pk][ck]
            if not self._values[pk]:
                del self._values[pk]
        else:
            del self._values[key]

    def __eq__(self, other):
        """Check for equality against the other value

        :param other: The value to compare
        :type other: FlatDict
        :rtype: bool
        :raises: TypeError

        """
        if isinstance(other, dict):
            return sorted(self.as_dict()) == sorted(other)
        elif not isinstance(other, self.__class__):
            raise TypeError
        return sorted(self.as_dict()) == sorted(other.as_dict())

    def __ne__(self, other):
        """Check for inequality against the other value

        :param other: The value to compare
        :type other: dict or FlatDict
        :rtype: bool

        """
        return not self.__eq__(other)

    def __getitem__(self, key):
        """Get an item for the specified key, automatically dealing with
        nested children.

        :param mixed key: The key to use
        :rtype: mixed
        :raises: KeyError

        """
        values = self._values
        for part in key.split(self._delimiter):
            values = values[part]
        return values

    def __iter__(self):
        """Iterate over the flat dictionary key and values

        :rtype: Iterator
        :raises: RuntimeError

        """
        return iter(self.keys())

    def __len__(self):
        """Return the number of items.

        :rtype: int

        """
        return len(self.keys())

    def __reduce__(self):
        """Return state information for pickling

        :rtype: tuple

        """
        return type(self), (self.as_dict(), self._delimiter)

    def __repr__(self):
        """Return the string representation of the instance.

        :rtype: str

        """
        return '<{} id={} {}>"'.format(self.__class__.__name__, id(self),
                                       str(self))

    def __setitem__(self, key, value):
        """Assign the value to the key, dynamically building nested
        FlatDict items where appropriate.

        :param mixed key: The key for the item
        :param mixed value: The value for the item
        :raises: TypeError

        """
        if isinstance(value, self._COERCE) and not isinstance(value, FlatDict):
            value = self.__class__(value, self._delimiter)
        if self._has_delimiter(key):
            pk, ck = key.split(self._delimiter, 1)
            if pk not in self._values:
                self._values[pk] = self.__class__({ck: value}, self._delimiter)
                return
            elif not isinstance(self._values[pk], FlatDict):
                raise TypeError(
                    'Assignment to invalid type for key {}'.format(pk))
            self._values[pk][ck] = value
        else:
            self._values[key] = value

    def __str__(self):
        """Return the string value of the instance.

        :rtype: str

        """
        return '{{{}}}'.format(', '.join(
            ['{!r}: {!r}'.format(k, self[k]) for k in self.keys()]))

    def as_dict(self):
        """Return the :class:`~flatdict.FlatDict` as a :class:`dict`

        :rtype: dict

        """
        out = dict({})
        for key in self.keys():
            if self._has_delimiter(key):
                pk, ck = key.split(self._delimiter, 1)
                if self._has_delimiter(ck):
                    ck = ck.split(self._delimiter, 1)[0]
                if isinstance(self._values[pk], FlatDict) and pk not in out:
                    out[pk] = {}
                if isinstance(self._values[pk][ck], FlatDict):
                    out[pk][ck] = self._values[pk][ck].as_dict()
                else:
                    out[pk][ck] = self._values[pk][ck]
            else:
                out[key] = self._values[key]
        return out

    def clear(self):
        """Remove all items from the flat dictionary."""
        self._values.clear()

    def copy(self):
        """Return a shallow copy of the flat dictionary.

        :rtype: flatdict.FlatDict

        """
        return self.__class__(self.as_dict(), delimiter=self._delimiter)

    def get(self, key, d=None):
        """Return the value for key if key is in the flat dictionary, else
        default. If default is not given, it defaults to ``None``, so that this
        method never raises :exc:`KeyError`.

        :param mixed key: The key to get
        :param mixed d: The default value
        :rtype: mixed

        """
        try:
            return self.__getitem__(key)
        except KeyError:
            return d

    def items(self):
        """Return a copy of the flat dictionary's list of ``(key, value)``
        pairs.

        .. note:: CPython implementation detail: Keys and values are listed in
            an arbitrary order which is non-random, varies across Python
            implementations, and depends on the flat dictionary's history of
            insertions and deletions.

        :rtype: list

        """
        return [(k, self.__getitem__(k)) for k in self.keys()]

    def iteritems(self):
        """Return an iterator over the flat dictionary's (key, value) pairs.
        See the note for :meth:`flatdict.FlatDict.items`.

        Using ``iteritems()`` while adding or deleting entries in the flat
        dictionary may raise :exc:`RuntimeError` or fail to iterate over all
        entries.

        :rtype: Iterator
        :raises: RuntimeError

        """
        for item in self.items():
            yield item

    def iterkeys(self):
        """Iterate over the flat dictionary's keys. See the note for
        :meth:`flatdict.FlatDict.items`.

        Using ``iterkeys()`` while adding or deleting entries in the flat
        dictionary may raise :exc:`RuntimeError` or fail to iterate over all
        entries.

        :rtype: Iterator
        :raises: RuntimeError

        """
        for key in self.keys():
            yield key

    def itervalues(self):
        """Return an iterator over the flat dictionary's values. See the note
        :meth:`flatdict.FlatDict.items`.

        Using ``itervalues()`` while adding or deleting entries in the flat
        dictionary may raise a :exc:`RuntimeError` or fail to iterate over all
        entries.

        :rtype: Iterator
        :raises: RuntimeError

        """
        for value in self.values():
            yield value

    def keys(self):
        """Return a copy of the flat dictionary's list of keys.
        See the note for :meth:`flatdict.FlatDict.items`.

        :rtype: list

        """
        keys = []
        for key, value in self._values.items():
            if isinstance(value, (FlatDict, dict)):
                nested = [self._delimiter.join([key, k]) for k in value.keys()]
                keys += nested if nested else [key]
            else:
                keys.append(key)
        return sorted(keys)

    def pop(self, key, default=NO_DEFAULT):
        """If key is in the flat dictionary, remove it and return its value,
        else return default. If default is not given and key is not in the
        dictionary, :exc:`KeyError` is raised.

        :param mixed key: The key name
        :param mixed default: The default value
        :rtype: mixed

        """
        if key not in self and default != NO_DEFAULT:
            return default
        value = self[key]
        self.__delitem__(key)
        return value

    def setdefault(self, key, default):
        """If key is in the flat dictionary, return its value. If not,
        insert key with a value of default and return default.
        default defaults to ``None``.

        :param mixed key: The key name
        :param mixed default: The default value
        :rtype: mixed

        """
        if key not in self or not self.__getitem__(key):
            self.__setitem__(key, default)
        return self.__getitem__(key)

    def set_delimiter(self, delimiter):
        """Override the default or passed in delimiter with a new value. If
        the requested delimiter already exists in a key, a :exc:`ValueError`
        will be raised.

        :param str delimiter: The delimiter to use
        :raises: ValueError

        """
        for key in self.keys():
            if delimiter in key:
                raise ValueError('Key {!r} collides with delimiter {!r}', key,
                                 delimiter)
        self._delimiter = delimiter
        for key in self._values.keys():
            if isinstance(self._values[key], FlatDict):
                self._values[key].set_delimiter(delimiter)

    def update(self, other=None, **kwargs):
        """Update the flat dictionary with the key/value pairs from other,
        overwriting existing keys.

        ``update()`` accepts either another flat dictionary object or an
        iterable of key/value pairs (as tuples or other iterables of length
        two). If keyword arguments are specified, the flat dictionary is then
        updated with those key/value pairs: ``d.update(red=1, blue=2)``.

        :param iterable other: Iterable of key, value pairs
        :rtype: None

        """
        [self.__setitem__(k, v) for k, v in dict(other or kwargs).items()]

    def values(self):
        """Return a copy of the flat dictionary's list of values. See the note
        for :meth:`flatdict.FlatDict.items`.

        :rtype: list

        """
        return [self.__getitem__(k) for k in self.keys()]

    def _has_delimiter(self, key):
        """Checks to see if the key contains the delimiter.

        :rtype: bool

        """
        return isinstance(key, basestring) and self._delimiter in key

class FlatterDict(FlatDict):
    """Like :class:`~flatdict.FlatDict` but also coerces lists and sets
     to child-dict instances with the offset as the key. Alternative to
     the implementation added in v1.2 of FlatDict.

    """
    _COERCE = list, tuple, set, dict, FlatDict
    _ARRAYS = list, set, tuple

    def __init__(self, value=None, delimiter=':'):
        self.original_type = type(value)
        if self.original_type in self._ARRAYS:
            value = {str(i): v for i, v in enumerate(value)}
        super(FlatterDict, self).__init__(value, delimiter)

    def __setitem__(self, key, value):
        """Assign the value to the key, dynamically building nested
        FlatDict items where appropriate.

        :param mixed key: The key for the item
        :param mixed value: The value for the item
        :raises: TypeError

        """
        if isinstance(value, self._COERCE) and \
                not isinstance(value, FlatterDict):
            value = self.__class__(value, self._delimiter)
        if self._has_delimiter(key):
            pk, ck = key.split(self._delimiter, 1)
            if pk not in self._values:
                self._values[pk] = self.__class__({ck: value}, self._delimiter)
                return
            if getattr(self._values[pk], 'original_type',
                       None) in self._ARRAYS:
                try:
                    int(ck)
                except ValueError:
                    raise TypeError(
                        'Assignment to invalid type for key {}{}{}'.format(
                            pk, self._delimiter, ck))
            elif not isinstance(self._values[pk], FlatterDict):
                raise TypeError(
                    'Assignment to invalid type for key {}'.format(pk))
            self._values[pk][ck] = value
        else:
            self._values[key] = value

    def as_dict(self):
        """Return the :class:`~flatdict.FlatterDict` as a nested
        :class:`dict`.

        :rtype: dict

        """
        out = {}
        for key in self.keys():
            if self._has_delimiter(key):
                pk, ck = key.split(self._delimiter, 1)
                if self._has_delimiter(ck):
                    ck = ck.split(self._delimiter, 1)[0]
                if isinstance(self._values[pk], FlatterDict) and pk not in out:
                    if self._values[pk].original_type == tuple:
                        out[pk] = tuple(self._child_as_list(pk))
                    elif self._values[pk].original_type == list:
                        out[pk] = self._child_as_list(pk)
                    elif self._values[pk].original_type == set:
                        out[pk] = set(self._child_as_list(pk))
                    elif self._values[pk].original_type == dict:
                        out[pk] = self._values[pk].as_dict()
            else:
                if isinstance(self._values[key], FlatterDict):
                    out[key] = self._values[key].original_type()
                else:
                    out[key] = self._values[key]
        return out

    def _child_as_list(self, pk, ck=None):
        """Returns a list of values from the child FlatterDict instance
        with string based integer keys.

        :param str pk: The parent key
        :param str ck: The child key, optional
        :rtype: list

        """
        if ck is None:
            subset = self._values[pk]
        else:
            subset = self._values[pk][ck]
        # Check if keys has delimiter, which implies deeply nested dict
        keys = subset.keys()
        if any(self._has_delimiter(k) for k in keys):
            out = []
            split_keys = [k.split(self._delimiter)[0] for k in keys]
            for k in sorted(set(split_keys)):
                if subset[k].original_type == tuple:
                    out.append(tuple(self._child_as_list(pk, k)))
                elif subset[k].original_type == list:
                    out.append(self._child_as_list(pk, k))
                elif subset[k].original_type == set:
                    out.append(set(self._child_as_list(pk, k)))
                elif subset[k].original_type == dict:
                    out.append(subset[k].as_dict())
            return out
        return [subset[k] for k in sorted(keys, key=lambda x: int(x))]
<commit_msg>bump version<commit_after>"""FlatDict is a dict object that allows for single level, delimited
key/value pair mapping of nested dictionaries.

"""
import collections

__version__ = '3.2.2'

NO_DEFAULT = object()

# Python 2/3 string compat
try:
    basestring
except NameError:
    basestring = str

class FlatDict(collections.MutableMapping):
    """:class:`~flatdict.FlatDict` is a dictionary object that allows for
    single level, delimited key/value pair mapping of nested dictionaries.
    The default delimiter value is ``:`` but can be changed in the constructor
    or by calling :meth:`FlatDict.set_delimiter`.

    """
    _COERCE = dict

    def __init__(self, value=None, delimiter=':'):
        super(FlatDict, self).__init__()
        self._values = {}
        self._delimiter = delimiter
        self.update(value)

    def __contains__(self, key):
        """Check to see if the key exists, checking for both delimited and
        not delimited key values.

        :param mixed key: The key to check for

        """
        if self._has_delimiter(key):
            pk, ck = key.split(self._delimiter, 1)
            return pk in self._values and ck in self._values[pk]
        return key in self._values

    def __delitem__(self, key):
        """Delete the item for the specified key, automatically dealing with
        nested children.

        :param mixed key: The key to use
        :raises: KeyError

        """
        if key not in self:
            raise KeyError
        if self._has_delimiter(key):
            pk, ck = key.split(self._delimiter, 1)
            del self._values[pk][ck]
            if not self._values[pk]:
                del self._values[pk]
        else:
            del self._values[key]

    def __eq__(self, other):
        """Check for equality against the other value

        :param other: The value to compare
        :type other: FlatDict
        :rtype: bool
        :raises: TypeError

        """
        if isinstance(other, dict):
            return sorted(self.as_dict()) == sorted(other)
        elif not isinstance(other, self.__class__):
            raise TypeError
        return sorted(self.as_dict()) == sorted(other.as_dict())

    def __ne__(self, other):
        """Check for inequality against the other value

        :param other: The value to compare
        :type other: dict or FlatDict
        :rtype: bool

        """
        return not self.__eq__(other)

    def __getitem__(self, key):
        """Get an item for the specified key, automatically dealing with
        nested children.

        :param mixed key: The key to use
        :rtype: mixed
        :raises: KeyError

        """
        values = self._values
        for part in key.split(self._delimiter):
            values = values[part]
        return values

    def __iter__(self):
        """Iterate over the flat dictionary key and values

        :rtype: Iterator
        :raises: RuntimeError

        """
        return iter(self.keys())

    def __len__(self):
        """Return the number of items.

        :rtype: int

        """
        return len(self.keys())

    def __reduce__(self):
        """Return state information for pickling

        :rtype: tuple

        """
        return type(self), (self.as_dict(), self._delimiter)

    def __repr__(self):
        """Return the string representation of the instance.

        :rtype: str

        """
        return '<{} id={} {}>"'.format(self.__class__.__name__, id(self),
                                       str(self))

    def __setitem__(self, key, value):
        """Assign the value to the key, dynamically building nested
        FlatDict items where appropriate.

        :param mixed key: The key for the item
        :param mixed value: The value for the item
        :raises: TypeError

        """
        if isinstance(value, self._COERCE) and not isinstance(value, FlatDict):
            value = self.__class__(value, self._delimiter)
        if self._has_delimiter(key):
            pk, ck = key.split(self._delimiter, 1)
            if pk not in self._values:
                self._values[pk] = self.__class__({ck: value}, self._delimiter)
                return
            elif not isinstance(self._values[pk], FlatDict):
                raise TypeError(
                    'Assignment to invalid type for key {}'.format(pk))
            self._values[pk][ck] = value
        else:
            self._values[key] = value

    def __str__(self):
        """Return the string value of the instance.

        :rtype: str

        """
        return '{{{}}}'.format(', '.join(
            ['{!r}: {!r}'.format(k, self[k]) for k in self.keys()]))

    def as_dict(self):
        """Return the :class:`~flatdict.FlatDict` as a :class:`dict`

        :rtype: dict

        """
        out = dict({})
        for key in self.keys():
            if self._has_delimiter(key):
                pk, ck = key.split(self._delimiter, 1)
                if self._has_delimiter(ck):
                    ck = ck.split(self._delimiter, 1)[0]
                if isinstance(self._values[pk], FlatDict) and pk not in out:
                    out[pk] = {}
                if isinstance(self._values[pk][ck], FlatDict):
                    out[pk][ck] = self._values[pk][ck].as_dict()
                else:
                    out[pk][ck] = self._values[pk][ck]
            else:
                out[key] = self._values[key]
        return out

    def clear(self):
        """Remove all items from the flat dictionary."""
        self._values.clear()

    def copy(self):
        """Return a shallow copy of the flat dictionary.

        :rtype: flatdict.FlatDict

        """
        return self.__class__(self.as_dict(), delimiter=self._delimiter)

    def get(self, key, d=None):
        """Return the value for key if key is in the flat dictionary, else
        default. If default is not given, it defaults to ``None``, so that this
        method never raises :exc:`KeyError`.

        :param mixed key: The key to get
        :param mixed d: The default value
        :rtype: mixed

        """
        try:
            return self.__getitem__(key)
        except KeyError:
            return d

    def items(self):
        """Return a copy of the flat dictionary's list of ``(key, value)``
        pairs.

        .. note:: CPython implementation detail: Keys and values are listed in
            an arbitrary order which is non-random, varies across Python
            implementations, and depends on the flat dictionary's history of
            insertions and deletions.

        :rtype: list

        """
        return [(k, self.__getitem__(k)) for k in self.keys()]

    def iteritems(self):
        """Return an iterator over the flat dictionary's (key, value) pairs.
        See the note for :meth:`flatdict.FlatDict.items`.

        Using ``iteritems()`` while adding or deleting entries in the flat
        dictionary may raise :exc:`RuntimeError` or fail to iterate over all
        entries.

        :rtype: Iterator
        :raises: RuntimeError

        """
        for item in self.items():
            yield item

    def iterkeys(self):
        """Iterate over the flat dictionary's keys. See the note for
        :meth:`flatdict.FlatDict.items`.

        Using ``iterkeys()`` while adding or deleting entries in the flat
        dictionary may raise :exc:`RuntimeError` or fail to iterate over all
        entries.

        :rtype: Iterator
        :raises: RuntimeError

        """
        for key in self.keys():
            yield key

    def itervalues(self):
        """Return an iterator over the flat dictionary's values. See the note
        :meth:`flatdict.FlatDict.items`.

        Using ``itervalues()`` while adding or deleting entries in the flat
        dictionary may raise a :exc:`RuntimeError` or fail to iterate over all
        entries.

        :rtype: Iterator
        :raises: RuntimeError

        """
        for value in self.values():
            yield value

    def keys(self):
        """Return a copy of the flat dictionary's list of keys.
        See the note for :meth:`flatdict.FlatDict.items`.

        :rtype: list

        """
        keys = []
        for key, value in self._values.items():
            if isinstance(value, (FlatDict, dict)):
                nested = [self._delimiter.join([key, k]) for k in value.keys()]
                keys += nested if nested else [key]
            else:
                keys.append(key)
        return sorted(keys)

    def pop(self, key, default=NO_DEFAULT):
        """If key is in the flat dictionary, remove it and return its value,
        else return default. If default is not given and key is not in the
        dictionary, :exc:`KeyError` is raised.

        :param mixed key: The key name
        :param mixed default: The default value
        :rtype: mixed

        """
        if key not in self and default != NO_DEFAULT:
            return default
        value = self[key]
        self.__delitem__(key)
        return value

    def setdefault(self, key, default):
        """If key is in the flat dictionary, return its value. If not,
        insert key with a value of default and return default.
        default defaults to ``None``.

        :param mixed key: The key name
        :param mixed default: The default value
        :rtype: mixed

        """
        if key not in self or not self.__getitem__(key):
            self.__setitem__(key, default)
        return self.__getitem__(key)

    def set_delimiter(self, delimiter):
        """Override the default or passed in delimiter with a new value. If
        the requested delimiter already exists in a key, a :exc:`ValueError`
        will be raised.

        :param str delimiter: The delimiter to use
        :raises: ValueError

        """
        for key in self.keys():
            if delimiter in key:
                raise ValueError('Key {!r} collides with delimiter {!r}', key,
                                 delimiter)
        self._delimiter = delimiter
        for key in self._values.keys():
            if isinstance(self._values[key], FlatDict):
                self._values[key].set_delimiter(delimiter)

    def update(self, other=None, **kwargs):
        """Update the flat dictionary with the key/value pairs from other,
        overwriting existing keys.

        ``update()`` accepts either another flat dictionary object or an
        iterable of key/value pairs (as tuples or other iterables of length
        two). If keyword arguments are specified, the flat dictionary is then
        updated with those key/value pairs: ``d.update(red=1, blue=2)``.

        :param iterable other: Iterable of key, value pairs
        :rtype: None

        """
        [self.__setitem__(k, v) for k, v in dict(other or kwargs).items()]

    def values(self):
        """Return a copy of the flat dictionary's list of values. See the note
        for :meth:`flatdict.FlatDict.items`.

        :rtype: list

        """
        return [self.__getitem__(k) for k in self.keys()]

    def _has_delimiter(self, key):
        """Checks to see if the key contains the delimiter.

        :rtype: bool

        """
        return isinstance(key, basestring) and self._delimiter in key

class FlatterDict(FlatDict):
    """Like :class:`~flatdict.FlatDict` but also coerces lists and sets
     to child-dict instances with the offset as the key. Alternative to
     the implementation added in v1.2 of FlatDict.

    """
    _COERCE = list, tuple, set, dict, FlatDict
    _ARRAYS = list, set, tuple

    def __init__(self, value=None, delimiter=':'):
        self.original_type = type(value)
        if self.original_type in self._ARRAYS:
            value = {str(i): v for i, v in enumerate(value)}
        super(FlatterDict, self).__init__(value, delimiter)

    def __setitem__(self, key, value):
        """Assign the value to the key, dynamically building nested
        FlatDict items where appropriate.

        :param mixed key: The key for the item
        :param mixed value: The value for the item
        :raises: TypeError

        """
        if isinstance(value, self._COERCE) and \
                not isinstance(value, FlatterDict):
            value = self.__class__(value, self._delimiter)
        if self._has_delimiter(key):
            pk, ck = key.split(self._delimiter, 1)
            if pk not in self._values:
                self._values[pk] = self.__class__({ck: value}, self._delimiter)
                return
            if getattr(self._values[pk], 'original_type',
                       None) in self._ARRAYS:
                try:
                    int(ck)
                except ValueError:
                    raise TypeError(
                        'Assignment to invalid type for key {}{}{}'.format(
                            pk, self._delimiter, ck))
            elif not isinstance(self._values[pk], FlatterDict):
                raise TypeError(
                    'Assignment to invalid type for key {}'.format(pk))
            self._values[pk][ck] = value
        else:
            self._values[key] = value

    def as_dict(self):
        """Return the :class:`~flatdict.FlatterDict` as a nested
        :class:`dict`.

        :rtype: dict

        """
        out = {}
        for key in self.keys():
            if self._has_delimiter(key):
                pk, ck = key.split(self._delimiter, 1)
                if self._has_delimiter(ck):
                    ck = ck.split(self._delimiter, 1)[0]
                if isinstance(self._values[pk], FlatterDict) and pk not in out:
                    if self._values[pk].original_type == tuple:
                        out[pk] = tuple(self._child_as_list(pk))
                    elif self._values[pk].original_type == list:
                        out[pk] = self._child_as_list(pk)
                    elif self._values[pk].original_type == set:
                        out[pk] = set(self._child_as_list(pk))
                    elif self._values[pk].original_type == dict:
                        out[pk] = self._values[pk].as_dict()
            else:
                if isinstance(self._values[key], FlatterDict):
                    out[key] = self._values[key].original_type()
                else:
                    out[key] = self._values[key]
        return out

    def _child_as_list(self, pk, ck=None):
        """Returns a list of values from the child FlatterDict instance
        with string based integer keys.

        :param str pk: The parent key
        :param str ck: The child key, optional
        :rtype: list

        """
        if ck is None:
            subset = self._values[pk]
        else:
            subset = self._values[pk][ck]
        # Check if keys has delimiter, which implies deeply nested dict
        keys = subset.keys()
        if any(self._has_delimiter(k) for k in keys):
            out = []
            split_keys = [k.split(self._delimiter)[0] for k in keys]
            for k in sorted(set(split_keys)):
                if subset[k].original_type == tuple:
                    out.append(tuple(self._child_as_list(pk, k)))
                elif subset[k].original_type == list:
                    out.append(self._child_as_list(pk, k))
                elif subset[k].original_type == set:
                    out.append(set(self._child_as_list(pk, k)))
                elif subset[k].original_type == dict:
                    out.append(subset[k].as_dict())
            return out
        return [subset[k] for k in sorted(keys, key=lambda x: int(x))]
<|endoftext|>