<commit_before># encoding: utf-8

"""
.. codeauthor:: Tsuyoshi Hombashi <tsuyoshi.hombashi@gmail.com>
"""

from __future__ import absolute_import
from __future__ import unicode_literals

import copy

import dataproperty
from typepy import Typecode

from .._const import TableFormat
from .._logger import logger
from ._table_writer import AbstractTableWriter

class ElasticsearchWriter(AbstractTableWriter):
    """
    A table writer class for Elasticsearch.

    .. py:method:: write_table()

        Create an index and put documents for each row to Elasticsearch.

        :raises ValueError:
            If the |stream| has not elasticsearch.Elasticsearch instance.

    .. py:attribute:: document_type

        Specify document type for indices. Defaults to ``"table"``.

    :Examples:

        :ref:`example-elasticsearch-table-writer`
    """

    @property
    def format_name(self):
        return TableFormat.ELASTICSEARCH

    @property
    def support_split_write(self):
        return True

    def __init__(self):
        super(ElasticsearchWriter, self).__init__()

        self.stream = None
        self.is_padding = False
        self.is_float_formatting = False
        self._is_required_table_name = True
        self._quote_flag_mapping = copy.deepcopy(
            dataproperty.NULL_QUOTE_FLAG_MAPPING)
        self._dp_extractor.type_value_mapping = copy.deepcopy(
            dataproperty.DefaultValue.TYPE_VALUE_MAPPING)

        self.document_type = "table"

    def write_null_line(self):
        pass

    def __get_es_datatype(self, column_dp):
        if column_dp.typecode in (Typecode.STRING, Typecode.NULL_STRING):
            return {"type": "string"}

        if column_dp.typecode == Typecode.DATETIME:
            return {"type": "date", "format": "date_optional_time"}

        if column_dp.typecode == Typecode.REAL_NUMBER:
            return {"type": "double"}

        if column_dp.typecode == Typecode.BOOL:
            return {"type": "boolean"}

        if column_dp.typecode == Typecode.IP_ADDRESS:
            return {"type": "ip"}

        if column_dp.typecode == Typecode.INTEGER:
            if column_dp.bit_length <= 8:
                return {"type": "byte"}
            elif column_dp.bit_length <= 16:
                return {"type": "short"}
            elif column_dp.bit_length <= 32:
                return {"type": "integer"}
            elif column_dp.bit_length <= 64:
                return {"type": "long"}

            raise ValueError(
                "too large integer bits: "
                "expected<=64bits, actual={:d}bits".format(
                    column_dp.bit_length))

        if column_dp.typecode == Typecode.NONE:
            return {"type": "string"}

        if column_dp.typecode in (Typecode.INFINITY, Typecode.NAN):
            return {"type": "keyword"}

        raise ValueError("unknown typecode: {}".format(column_dp.typecode))

    def _get_mappings(self):
        properties = {}

        for header, column_dp in zip(self.header_list, self._column_dp_list):
            properties[header] = self.__get_es_datatype(column_dp)

        return {
            "mappings": {
                self.document_type: {
                    "properties": properties
                }
            }
        }

    def _get_body(self):
        str_datatype = (
            Typecode.DATETIME, Typecode.IP_ADDRESS,
            Typecode.INFINITY, Typecode.NAN,
        )

        for value_dp_list in self._value_dp_matrix:
            value_list = [
                value_dp.data if value_dp.typecode not in str_datatype else value_dp.to_str()
                for value_dp in value_dp_list
            ]

            yield dict(zip(self.header_list, value_list))

    def _write_table(self):
        import elasticsearch as es

        if not isinstance(self.stream, es.Elasticsearch):
            raise ValueError(
                "stream must be a elasticsearch.Elasticsearch instance")

        self._verify_property()
        self._verify_value_matrix()
        self._preprocess()

        index_name = self.table_name
        mappings = self._get_mappings()

        try:
            result = self.stream.indices.create(
                index=index_name, body=mappings)
            logger.debug(result)
        except es.TransportError as e:
            if e.error == "index_already_exists_exception":
                # ignore already existing index
                logger.debug(e)
            else:
                raise

        for body in self._get_body():
            try:
                self.stream.index(
                    index=index_name, body=body, doc_type=self.document_type)
            except es.exceptions.RequestError as e:
                logger.error("message={}, body={}".format(e, body))

    def _write_value_row_separator(self):
        pass
<commit_msg>Update a docstring<commit_after># encoding: utf-8

"""
.. codeauthor:: Tsuyoshi Hombashi <tsuyoshi.hombashi@gmail.com>
"""

from __future__ import absolute_import
from __future__ import unicode_literals

import copy

import dataproperty
from typepy import Typecode

from .._const import TableFormat
from .._logger import logger
from ._table_writer import AbstractTableWriter

class ElasticsearchWriter(AbstractTableWriter):
    """
    A table writer class for Elasticsearch.

    .. py:method:: write_table()

        Create an index and put documents for each row to Elasticsearch.
        Document data types for documents are automatically detected
        from the data.

        :raises ValueError:
            If the |stream| has not elasticsearch.Elasticsearch instance.

    .. py:attribute:: document_type

        Specify document type for indices. Defaults to ``"table"``.

    :Examples:

        :ref:`example-elasticsearch-table-writer`
    """

    @property
    def format_name(self):
        return TableFormat.ELASTICSEARCH

    @property
    def support_split_write(self):
        return True

    def __init__(self):
        super(ElasticsearchWriter, self).__init__()

        self.stream = None
        self.is_padding = False
        self.is_float_formatting = False
        self._is_required_table_name = True
        self._quote_flag_mapping = copy.deepcopy(
            dataproperty.NULL_QUOTE_FLAG_MAPPING)
        self._dp_extractor.type_value_mapping = copy.deepcopy(
            dataproperty.DefaultValue.TYPE_VALUE_MAPPING)

        self.document_type = "table"

    def write_null_line(self):
        pass

    def __get_es_datatype(self, column_dp):
        if column_dp.typecode in (Typecode.STRING, Typecode.NULL_STRING):
            return {"type": "string"}

        if column_dp.typecode == Typecode.DATETIME:
            return {"type": "date", "format": "date_optional_time"}

        if column_dp.typecode == Typecode.REAL_NUMBER:
            return {"type": "double"}

        if column_dp.typecode == Typecode.BOOL:
            return {"type": "boolean"}

        if column_dp.typecode == Typecode.IP_ADDRESS:
            return {"type": "ip"}

        if column_dp.typecode == Typecode.INTEGER:
            if column_dp.bit_length <= 8:
                return {"type": "byte"}
            elif column_dp.bit_length <= 16:
                return {"type": "short"}
            elif column_dp.bit_length <= 32:
                return {"type": "integer"}
            elif column_dp.bit_length <= 64:
                return {"type": "long"}

            raise ValueError(
                "too large integer bits: "
                "expected<=64bits, actual={:d}bits".format(
                    column_dp.bit_length))

        if column_dp.typecode == Typecode.NONE:
            return {"type": "string"}

        if column_dp.typecode in (Typecode.INFINITY, Typecode.NAN):
            return {"type": "keyword"}

        raise ValueError("unknown typecode: {}".format(column_dp.typecode))

    def _get_mappings(self):
        properties = {}

        for header, column_dp in zip(self.header_list, self._column_dp_list):
            properties[header] = self.__get_es_datatype(column_dp)

        return {
            "mappings": {
                self.document_type: {
                    "properties": properties
                }
            }
        }

    def _get_body(self):
        str_datatype = (
            Typecode.DATETIME, Typecode.IP_ADDRESS,
            Typecode.INFINITY, Typecode.NAN,
        )

        for value_dp_list in self._value_dp_matrix:
            value_list = [
                value_dp.data if value_dp.typecode not in str_datatype else value_dp.to_str()
                for value_dp in value_dp_list
            ]

            yield dict(zip(self.header_list, value_list))

    def _write_table(self):
        import elasticsearch as es

        if not isinstance(self.stream, es.Elasticsearch):
            raise ValueError(
                "stream must be a elasticsearch.Elasticsearch instance")

        self._verify_property()
        self._verify_value_matrix()
        self._preprocess()

        index_name = self.table_name
        mappings = self._get_mappings()

        try:
            result = self.stream.indices.create(
                index=index_name, body=mappings)
            logger.debug(result)
        except es.TransportError as e:
            if e.error == "index_already_exists_exception":
                # ignore already existing index
                logger.debug(e)
            else:
                raise

        for body in self._get_body():
            try:
                self.stream.index(
                    index=index_name, body=body, doc_type=self.document_type)
            except es.exceptions.RequestError as e:
                logger.error("message={}, body={}".format(e, body))

    def _write_value_row_separator(self):
        pass
<|endoftext|>


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

import Gaffer

import GafferUI

class CompoundPathPreview( GafferUI.PathPreviewWidget ) :

	## If specified, childTypes should be a tuple of names of types
	# registered with PathPreviewWidget - each type will be
	# instantiated to become a tab in the CompoundPathPreview.
	# If not specified, then all registered types are used.
	def __init__( self, path, childTypes=None, **kw ) :

		self.__tabbedContainer = GafferUI.TabbedContainer()

		GafferUI.PathPreviewWidget.__init__( self, self.__tabbedContainer, path, **kw )

		if childTypes is None :
			childTypes = GafferUI.PathPreviewWidget.types()

		self.__labelsAndTabs = []
		for type in childTypes :
			widget = GafferUI.PathPreviewWidget.create( type, path )
			self.__labelsAndTabs.append( ( type, widget ) )

		self.__currentTabChangedConnection = self.__tabbedContainer.currentChangedSignal().connect( Gaffer.WeakMethod( self.__currentTabChanged ) )

		self.__preferredTab = None

		self._updateFromPath()

	def _updateFromPath( self ) :

		with Gaffer.BlockedConnection( self.__currentTabChangedConnection ) :

			del self.__tabbedContainer[:]
			for label, tab in self.__labelsAndTabs :
				tab.setPath( self.getPath() )
				if tab.isValid() :
					self.__tabbedContainer.append( tab, label=label )
					if label == self.__preferredTab :
						self.__tabbedContainer.setCurrent( tab )

	def __currentTabChanged( self, tabbedContainer, current ) :

		assert( tabbedContainer is self.__tabbedContainer )
		if current is not None :
			self.__preferredTab = self.__tabbedContainer.getLabel( current )<commit_msg>Improved CompoundPathPreview default tab choice.<commit_after>##########################################################################
#
#  Copyright (c) 2012, Image Engine Design Inc. All rights reserved.
#
#  Redistribution and use in source and binary forms, with or without
#  modification, are permitted provided that the following conditions are
#  met:
#
#      * Redistributions of source code must retain the above
#        copyright notice, this list of conditions and the following
#        disclaimer.
#
#      * Redistributions in binary form must reproduce the above
#        copyright notice, this list of conditions and the following
#        disclaimer in the documentation and/or other materials provided with
#        the distribution.
#
#      * Neither the name of John Haddon nor the names of
#        any other contributors to this software may be used to endorse or
#        promote products derived from this software without specific prior
#        written permission.
#
#  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
#  IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
#  THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
#  PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
#  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
#  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
#  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
#  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
#  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
#  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
#  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
##########################################################################

import Gaffer

import GafferUI

class CompoundPathPreview( GafferUI.PathPreviewWidget ) :

	## If specified, childTypes should be a tuple of names of types
	# registered with PathPreviewWidget - each type will be
	# instantiated to become a tab in the CompoundPathPreview.
	# If not specified, then all registered types are used.
	def __init__( self, path, childTypes=None, **kw ) :

		self.__tabbedContainer = GafferUI.TabbedContainer()

		GafferUI.PathPreviewWidget.__init__( self, self.__tabbedContainer, path, **kw )

		if childTypes is None :
			childTypes = GafferUI.PathPreviewWidget.types()

		self.__labelsAndTabs = []
		for type in childTypes :
			widget = GafferUI.PathPreviewWidget.create( type, path )
			self.__labelsAndTabs.append( ( type, widget ) )

		self.__currentTabChangedConnection = self.__tabbedContainer.currentChangedSignal().connect( Gaffer.WeakMethod( self.__currentTabChanged ) )

		self.__preferredTab = None

		self._updateFromPath()

	def _updateFromPath( self ) :

		with Gaffer.BlockedConnection( self.__currentTabChangedConnection ) :

			del self.__tabbedContainer[:]
			for label, tab in self.__labelsAndTabs :
				tab.setPath( self.getPath() )
				if tab.isValid() :
					self.__tabbedContainer.append( tab, label=label )
					if label == self.__preferredTab :
						self.__tabbedContainer.setCurrent( tab )

			if self.__preferredTab is None :
				self.__tabbedContainer.setCurrent( self.__tabbedContainer[-1] )

	def __currentTabChanged( self, tabbedContainer, current ) :

		assert( tabbedContainer is self.__tabbedContainer )
		if current is not None :
			self.__preferredTab = self.__tabbedContainer.getLabel( current )
<|endoftext|>


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

import maya.cmds

import IECore
import IECoreMaya

class VectorParameterUI( IECoreMaya.ParameterUI ) :

	def __init__( self, node, parameter, **kw ) :

		self.__dim = parameter.getTypedValue().dimensions()
		if self.__dim == 2:
			layout = maya.cmds.rowLayout(
				numberOfColumns = 3,
				columnWidth3 = [ IECoreMaya.ParameterUI.textColumnWidthIndex, IECoreMaya.ParameterUI.singleWidgetWidthIndex, IECoreMaya.ParameterUI.singleWidgetWidthIndex ]
			)
		elif self.__dim == 3:
			layout = maya.cmds.rowLayout(
				numberOfColumns = 4,
				columnWidth4 = [ IECoreMaya.ParameterUI.textColumnWidthIndex, IECoreMaya.ParameterUI.singleWidgetWidthIndex, IECoreMaya.ParameterUI.singleWidgetWidthIndex, IECoreMaya.ParameterUI.singleWidgetWidthIndex ]
			)
		else:
			raise RuntimeError("Unsupported vector dimension in VectorParameterUI")

		IECoreMaya.ParameterUI.__init__( self, node, parameter, layout, **kw )

		self.__fields = []

		maya.cmds.text(
			label = self.label(),
			font = "smallPlainLabelFont",
			align = "right",
			annotation = self.description()
		)

		plug = self.plug()
		for i in range(0, self.__dim) :
			self.__fields.append(
				self.__fieldType()(
					value = parameter.getTypedValue()[i]
				)
			)

		maya.cmds.setParent("..")

		self.replace( self.node(), self.parameter )

	def replace( self, node, parameter ) :

		IECoreMaya.ParameterUI.replace( self, node, parameter )

		plug = self.plug()
		for i in range(0, self.__dim):

			childPlugName = self.nodeName() + "." + plug.child(i).partialName()
			maya.cmds.connectControl( self.__fields[i], childPlugName )
			self._addPopupMenu( parentUI = self.__fields[i], attributeName = childPlugName )

	def __fieldType( self ):

		if self.parameter.isInstanceOf( IECore.TypeId.V2iParameter ) or self.parameter.isInstanceOf( IECore.TypeId.V3iParameter ):
			return maya.cmds.intField
		else:
			return maya.cmds.floatField

IECoreMaya.ParameterUI.registerUI( IECore.TypeId.V2iParameter, VectorParameterUI )
IECoreMaya.ParameterUI.registerUI( IECore.TypeId.V3iParameter, VectorParameterUI )
IECoreMaya.ParameterUI.registerUI( IECore.TypeId.V2fParameter, VectorParameterUI )
IECoreMaya.ParameterUI.registerUI( IECore.TypeId.V2dParameter, VectorParameterUI )
IECoreMaya.ParameterUI.registerUI( IECore.TypeId.V3fParameter, VectorParameterUI )
IECoreMaya.ParameterUI.registerUI( IECore.TypeId.V3dParameter, VectorParameterUI )
<commit_msg>Allowing colours to be shown as 3 float fields.<commit_after>##########################################################################
#
#  Copyright (c) 2010, Image Engine Design Inc. All rights reserved.
#
#  Redistribution and use in source and binary forms, with or without
#  modification, are permitted provided that the following conditions are
#  met:
#
#     * Redistributions of source code must retain the above copyright
#       notice, this list of conditions and the following disclaimer.
#
#     * Redistributions in binary form must reproduce the above copyright
#       notice, this list of conditions and the following disclaimer in the
#       documentation and/or other materials provided with the distribution.
#
#     * Neither the name of Image Engine Design nor the names of any
#       other contributors to this software may be used to endorse or
#       promote products derived from this software without specific prior
#       written permission.
#
#  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
#  IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
#  THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
#  PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
#  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
#  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
#  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
#  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
#  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
#  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
#  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
##########################################################################

import maya.cmds

import IECore
import IECoreMaya

class VectorParameterUI( IECoreMaya.ParameterUI ) :

	def __init__( self, node, parameter, **kw ) :

		self.__dim = parameter.getTypedValue().dimensions()
		if self.__dim == 2:
			layout = maya.cmds.rowLayout(
				numberOfColumns = 3,
				columnWidth3 = [ IECoreMaya.ParameterUI.textColumnWidthIndex, IECoreMaya.ParameterUI.singleWidgetWidthIndex, IECoreMaya.ParameterUI.singleWidgetWidthIndex ]
			)
		elif self.__dim == 3:
			layout = maya.cmds.rowLayout(
				numberOfColumns = 4,
				columnWidth4 = [ IECoreMaya.ParameterUI.textColumnWidthIndex, IECoreMaya.ParameterUI.singleWidgetWidthIndex, IECoreMaya.ParameterUI.singleWidgetWidthIndex, IECoreMaya.ParameterUI.singleWidgetWidthIndex ]
			)
		else:
			raise RuntimeError("Unsupported vector dimension in VectorParameterUI")

		IECoreMaya.ParameterUI.__init__( self, node, parameter, layout, **kw )

		self.__fields = []

		maya.cmds.text(
			label = self.label(),
			font = "smallPlainLabelFont",
			align = "right",
			annotation = self.description()
		)

		plug = self.plug()
		for i in range(0, self.__dim) :
			self.__fields.append(
				self.__fieldType()(
					value = parameter.getTypedValue()[i]
				)
			)

		maya.cmds.setParent("..")

		self.replace( self.node(), self.parameter )

	def replace( self, node, parameter ) :

		IECoreMaya.ParameterUI.replace( self, node, parameter )

		plug = self.plug()
		for i in range(0, self.__dim):

			childPlugName = self.nodeName() + "." + plug.child(i).partialName()
			maya.cmds.connectControl( self.__fields[i], childPlugName )
			self._addPopupMenu( parentUI = self.__fields[i], attributeName = childPlugName )

	def __fieldType( self ):

		if self.parameter.isInstanceOf( IECore.TypeId.V2iParameter ) or self.parameter.isInstanceOf( IECore.TypeId.V3iParameter ):
			return maya.cmds.intField
		else:
			return maya.cmds.floatField

IECoreMaya.ParameterUI.registerUI( IECore.TypeId.V2iParameter, VectorParameterUI )
IECoreMaya.ParameterUI.registerUI( IECore.TypeId.V3iParameter, VectorParameterUI )
IECoreMaya.ParameterUI.registerUI( IECore.TypeId.V2fParameter, VectorParameterUI )
IECoreMaya.ParameterUI.registerUI( IECore.TypeId.V2dParameter, VectorParameterUI )
IECoreMaya.ParameterUI.registerUI( IECore.TypeId.V3fParameter, VectorParameterUI )
IECoreMaya.ParameterUI.registerUI( IECore.TypeId.V3dParameter, VectorParameterUI )

IECoreMaya.ParameterUI.registerUI( IECore.TypeId.Color3fParameter, VectorParameterUI, "numeric" )
<|endoftext|>


<commit_before>#pylint: disable=missing-docstring

import os

from mooseutils.yaml_load import yaml_load

import MooseDocs
from MooseDocs.common import exceptions
from MooseDocs.extensions import command
from MooseDocs.tree import tokens

def make_extension(**kwargs):
    return PackageExtension(**kwargs)

class PackageExtension(command.CommandExtension):
    """
    Adds ability to link to MOOSE enviornment packages.
    """

    @staticmethod
    def defaultConfig():
        packages = yaml_load(os.path.join(MooseDocs.MOOSE_DIR, 'framework', 'doc',
                                                     'packages.yml'))

        config = command.CommandExtension.defaultConfig()
        config['packages'] = (packages, "A dict of packages by name.")
        config['link'] = (r'http://www.mooseframework.org/moose_packages',
                          "Location of packages.")
        return config

    def extend(self, reader, renderer):
        self.requires(command)
        self.addCommand(PackageCommand())

class PackageCommand(command.CommandComponent):
    COMMAND = 'package'
    SUBCOMMAND = 'name'

    @staticmethod
    def defaultSettings():
        settings = command.CommandComponent.defaultSettings()
        settings['arch'] = (None, "The name of the OS package name to retrieve.")
        return settings

    def createToken(self, info, parent):
        arch = self.settings['arch']
        packages = self.extension.get('packages')

        if arch not in packages:
            msg = "The supplied value for the 'arch' settings, {}, was not found."
            raise exceptions.TokenizeException(msg, arch)

        href = os.path.join(self.extension.get('link'), packages[arch])
        tokens.Link(parent, url=unicode(href), string=unicode(packages[arch]))
        return parent
<commit_msg>Fix pylint error<commit_after>#pylint: disable=missing-docstring

import os

from mooseutils.yaml_load import yaml_load

import MooseDocs
from MooseDocs.common import exceptions
from MooseDocs.extensions import command
from MooseDocs.tree import tokens

def make_extension(**kwargs):
    return PackageExtension(**kwargs)

class PackageExtension(command.CommandExtension):
    """
    Adds ability to link to MOOSE enviornment packages.
    """

    @staticmethod
    def defaultConfig():
        packages = yaml_load(os.path.join(MooseDocs.MOOSE_DIR, 'framework', 'doc', 'packages.yml'))

        config = command.CommandExtension.defaultConfig()
        config['packages'] = (packages, "A dict of packages by name.")
        config['link'] = (r'http://www.mooseframework.org/moose_packages',
                          "Location of packages.")
        return config

    def extend(self, reader, renderer):
        self.requires(command)
        self.addCommand(PackageCommand())

class PackageCommand(command.CommandComponent):
    COMMAND = 'package'
    SUBCOMMAND = 'name'

    @staticmethod
    def defaultSettings():
        settings = command.CommandComponent.defaultSettings()
        settings['arch'] = (None, "The name of the OS package name to retrieve.")
        return settings

    def createToken(self, info, parent):
        arch = self.settings['arch']
        packages = self.extension.get('packages')

        if arch not in packages:
            msg = "The supplied value for the 'arch' settings, {}, was not found."
            raise exceptions.TokenizeException(msg, arch)

        href = os.path.join(self.extension.get('link'), packages[arch])
        tokens.Link(parent, url=unicode(href), string=unicode(packages[arch]))
        return parent
<|endoftext|>


<commit_before>#!/usr/bin/env python
# ----------------------------------------------------------------------
# Numenta Platform for Intelligent Computing (NuPIC)
# Copyright (C) 2015, Numenta, Inc.  Unless you have an agreement
# with Numenta, Inc., for a separate license for this software code, the
# following terms and conditions apply:
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 3 as
# published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see http://www.gnu.org/licenses.
#
# http://numenta.org/licenses/
# ----------------------------------------------------------------------

import operator
import random
import time

from matplotlib import pyplot
import numpy

from nupic.data.inference_shifter import InferenceShifter
from nupic.frameworks.opf.modelfactory import ModelFactory
from nupic.research.monitor_mixin.trace import CountsTrace

from sequence_generator import SequenceGenerator

MIN_ORDER = 3
MAX_ORDER = 4
NUM_PREDICTIONS = 1

MODEL_PARAMS = {
  "model": "CLA",
  "version": 1,
  "predictAheadTime": None,
  "modelParams": {
    "inferenceType": "TemporalMultiStep",
    "sensorParams": {
      "verbosity" : 0,
      "encoders": {
        "element": {
          "fieldname": u"element",
          "name": u"element",
          "type": "SDRCategoryEncoder",
          "categoryList": range(SequenceGenerator.numSymbols(MAX_ORDER,
                                                             NUM_PREDICTIONS)),
          "n": 2048,
          "w": 41
        }
      },
      "sensorAutoReset" : None,
    },
      "spEnable": False,
      "spParams": {
        "spVerbosity" : 0,
        "globalInhibition": 1,
        "columnCount": 2048,
        "inputWidth": 0,
        "numActiveColumnsPerInhArea": 40,
        "seed": 1956,
        "columnDimensions": 0.5,
        "synPermConnected": 0.1,
        "synPermActiveInc": 0.1,
        "synPermInactiveDec": 0.01,
        "maxBoost": 0.0
    },
    "tpEnable" : True,
    "tpParams": {
      "verbosity": 0,
        "columnCount": 2048,
        "cellsPerColumn": 32,
        "inputWidth": 2048,
        "seed": 1960,
        "temporalImp": "tm_py",
        "newSynapseCount": 20,
        "maxSynapsesPerSegment": 128,
        "maxSegmentsPerCell": 128,
        "initialPerm": 0.21,
        "connectedPerm": 0.50,
        "permanenceInc": 0.1,
        "permanenceDec": 0.1,
        "globalDecay": 0.0,
        "maxAge": 0,
        "minThreshold": 15,
        "activationThreshold": 15,
        "outputType": "normal",
        "pamLength": 1,
      },
      "clParams": {
        "implementation": "cpp",
        "regionName" : "CLAClassifierRegion",
        "clVerbosity" : 0,
        "alpha": 0.0001,
        "steps": "1",
      },
      "trainSPNetOnlyIfRequested": False,
    },
}

def generateSequences():
  generator = SequenceGenerator(seed=42)
  sequences = []

  for order in xrange(MIN_ORDER, MAX_ORDER+1):
    sequences += generator.generate(order, NUM_PREDICTIONS)

  for sequence in sequences:
    print sequence

  return sequences

def movingAverage(a, n):
  weights = numpy.repeat(1.0, n)/n
  return numpy.convolve(a, weights, 'valid')

def plotMovingAverage(data, window):
  movingData = movingAverage(data, min(len(data), window))
  style = 'ro' if len(data) < window else ''
  pyplot.plot(range(len(movingData)), movingData, style)

def plotAccuracy(correct, window=100):
  pyplot.title("Accuracy over window={0}".format(window))
  plotMovingAverage(correct, window)

def plotTMStats(numPredictedActiveCells, numPredictedInactiveCells, numUnpredictedActiveColumns,
                window=100):
  pyplot.subplot(3, 1, 1)
  pyplot.title("# predicted => active cells over window={0}".format(window))
  plotMovingAverage(numPredictedActiveCells, window)

  pyplot.subplot(3, 1, 2)
  pyplot.title("# predicted => inactive cells over window={0}".format(window))
  plotMovingAverage(numPredictedInactiveCells, window)

  pyplot.subplot(3, 1, 3)
  pyplot.title("# unpredicted => active cells over window={0}".format(window))
  plotMovingAverage(numUnpredictedActiveColumns, window)

def plotTraces(tm, timestamp=int(time.time()), window=500):
  """
  Have to make the following change in NuPIC for this to work:

  --- a/nupic/research/TP_shim.py
  +++ b/nupic/research/TP_shim.py
  @@ -27,10 +27,13 @@ for use with OPF.
   import numpy

   from nupic.research.temporal_memory import TemporalMemory
  +from nupic.research.monitor_mixin.temporal_memory_monitor_mixin import (
  +  TemporalMemoryMonitorMixin)
  +class MonitoredTemporalMemory(TemporalMemoryMonitorMixin, TemporalMemory): pass

  -class TPShim(TemporalMemory):
  +class TPShim(MonitoredTemporalMemory):
  """
  traces = tm.mmGetDefaultTraces()
  traces = [trace for trace in traces if type(trace) is CountsTrace]

  t = len(traces)

  for i in xrange(t):
    trace = traces[i]
    pyplot.subplot(t, 1, i+1)
    pyplot.title(trace.title)
    pyplot.xlim(max(len(trace.data)-window, 0), len(trace.data))
    pyplot.plot(range(len(trace.data)), trace.data)

  pyplot.draw()
  # pyplot.savefig("tm-{0}.png".format(timestamp))

if __name__ == "__main__":
  model = ModelFactory.create(MODEL_PARAMS)
  model.enableInference({"predictedField": "element"})
  shifter = InferenceShifter()

  sequences = generateSequences()
  correct = []
  numPredictedActiveCells = []
  numPredictedInactiveCells = []
  numUnpredictedActiveColumns = []

  pyplot.ion()
  pyplot.show()

  from pylab import rcParams

  rcParams.update({'figure.autolayout': True})
  rcParams.update({'figure.facecolor': 'white'})
  rcParams.update({'ytick.labelsize': 8})

  for i in xrange(100000000):
    sequence = random.choice(sequences)

    for j, element in enumerate(sequence):
      result = shifter.shift(model.run({"element": element}))
      # print element, result.inferences["multiStepPredictions"][1]
      tm = model._getTPRegion().getSelf()._tfdr

      if j == len(sequence) - 2:
        tm.mmClearHistory()

      if j == len(sequence) - 1:
        bestPredictions = sorted(result.inferences["multiStepPredictions"][1].items(),
                                 key=operator.itemgetter(1),
                                 reverse=True)
        topPredictions = [int(round(a)) for a, b in bestPredictions[:NUM_PREDICTIONS]]

        print "Evaluation:", element, topPredictions, element in topPredictions

        correct.append(element in topPredictions)
        numPredictedActiveCells.append(len(tm.mmGetTracePredictedActiveCells().data[0]))
        numPredictedInactiveCells.append(len(tm.mmGetTracePredictedInactiveCells().data[0]))
        numUnpredictedActiveColumns.append(len(tm.mmGetTraceUnpredictedActiveColumns().data[0]))

        if i % 100 == 0:
          rcParams.update({'figure.figsize': (12, 6)})
          pyplot.figure(1)
          pyplot.clf()
          plotAccuracy(correct)
          pyplot.draw()

          # rcParams.update({'figure.figsize': (6, 12)})
          # pyplot.figure(2)
          # pyplot.clf()
          # tm = model._getTPRegion().getSelf()._tfdr
          # plotTraces(tm)

          pyplot.figure(2)
          pyplot.clf()
          plotTMStats(numPredictedActiveCells, numPredictedInactiveCells, numUnpredictedActiveColumns)
          pyplot.draw()

    model.resetSequenceStates()
<commit_msg>Add other sequence sets<commit_after>#!/usr/bin/env python
# ----------------------------------------------------------------------
# Numenta Platform for Intelligent Computing (NuPIC)
# Copyright (C) 2015, Numenta, Inc.  Unless you have an agreement
# with Numenta, Inc., for a separate license for this software code, the
# following terms and conditions apply:
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 3 as
# published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see http://www.gnu.org/licenses.
#
# http://numenta.org/licenses/
# ----------------------------------------------------------------------

import operator
import random
import time

from matplotlib import pyplot
import numpy

from nupic.data.inference_shifter import InferenceShifter
from nupic.frameworks.opf.modelfactory import ModelFactory
from nupic.research.monitor_mixin.trace import CountsTrace

from sequence_generator import SequenceGenerator

MIN_ORDER = 3
MAX_ORDER = 4
NUM_PREDICTIONS = 1

MODEL_PARAMS = {
  "model": "CLA",
  "version": 1,
  "predictAheadTime": None,
  "modelParams": {
    "inferenceType": "TemporalMultiStep",
    "sensorParams": {
      "verbosity" : 0,
      "encoders": {
        "element": {
          "fieldname": u"element",
          "name": u"element",
          "type": "SDRCategoryEncoder",
          "categoryList": range(SequenceGenerator.numSymbols(MAX_ORDER,
                                                             NUM_PREDICTIONS)),
          "n": 2048,
          "w": 41
        }
      },
      "sensorAutoReset" : None,
    },
      "spEnable": False,
      "spParams": {
        "spVerbosity" : 0,
        "globalInhibition": 1,
        "columnCount": 2048,
        "inputWidth": 0,
        "numActiveColumnsPerInhArea": 40,
        "seed": 1956,
        "columnDimensions": 0.5,
        "synPermConnected": 0.1,
        "synPermActiveInc": 0.1,
        "synPermInactiveDec": 0.01,
        "maxBoost": 0.0
    },
    "tpEnable" : True,
    "tpParams": {
      "verbosity": 0,
        "columnCount": 2048,
        "cellsPerColumn": 32,
        "inputWidth": 2048,
        "seed": 1960,
        "temporalImp": "tm_py",
        "newSynapseCount": 20,
        "maxSynapsesPerSegment": 128,
        "maxSegmentsPerCell": 128,
        "initialPerm": 0.21,
        "connectedPerm": 0.50,
        "permanenceInc": 0.1,
        "permanenceDec": 0.1,
        "globalDecay": 0.0,
        "maxAge": 0,
        "minThreshold": 15,
        "activationThreshold": 15,
        "outputType": "normal",
        "pamLength": 1,
      },
      "clParams": {
        "implementation": "cpp",
        "regionName" : "CLAClassifierRegion",
        "clVerbosity" : 0,
        "alpha": 0.0001,
        "steps": "1",
      },
      "trainSPNetOnlyIfRequested": False,
    },
}

def generateSequences():
  sequences = []

  # Generated sequences
  generator = SequenceGenerator(seed=42)

  for order in xrange(MIN_ORDER, MAX_ORDER+1):
    sequences += generator.generate(order, NUM_PREDICTIONS)

  # # Subutai's sequences
  # """
  # Make sure to change parameter 'categoryList' above to: "categoryList": range(18)
  # """
  # sequences = [
  #   [0, 1, 2, 3, 4, 5],
  #   [6, 3, 2, 5, 1, 7],
  #   [8, 9, 10, 11, 12, 13],
  #   [14, 1, 2, 3, 15, 16],
  #   [17, 4, 2, 3, 1, 5]
  # ]

  # # Two orders of sequences
  # sequences = [
  #   [4, 2, 5, 0],
  #   [4, 5, 2, 3],
  #   [1, 2, 5, 3],
  #   [1, 5, 2, 0],
  #   [5, 3, 6, 2, 0],
  #   [5, 2, 6, 3, 4],
  #   [1, 3, 6, 2, 4],
  #   [1, 2, 6, 3, 0]
  # ]

  # # Two orders of sequences (easier)
  # # """
  # # Make sure to change parameter 'categoryList' above to: "categoryList": range(13)
  # # """
  # sequences = [
  #   [4, 2, 5, 0],
  #   [4, 5, 2, 3],
  #   [1, 2, 5, 3],
  #   [1, 5, 2, 0],
  #   [11, 9, 12, 8, 6],
  #   [11, 8, 12, 9, 10],
  #   [7, 9, 12, 8, 10],
  #   [7, 8, 12, 9, 6]
  # ]

  for sequence in sequences:
    print sequence

  return sequences

def movingAverage(a, n):
  weights = numpy.repeat(1.0, n)/n
  return numpy.convolve(a, weights, 'valid')

def plotMovingAverage(data, window):
  movingData = movingAverage(data, min(len(data), window))
  style = 'ro' if len(data) < window else ''
  pyplot.plot(range(len(movingData)), movingData, style)

def plotAccuracy(correct, window=100):
  pyplot.title("Accuracy over window={0}".format(window))
  plotMovingAverage(correct, window)

def plotTMStats(numPredictedActiveCells, numPredictedInactiveCells, numUnpredictedActiveColumns,
                window=100):
  pyplot.subplot(3, 1, 1)
  pyplot.title("# predicted => active cells over window={0}".format(window))
  plotMovingAverage(numPredictedActiveCells, window)

  pyplot.subplot(3, 1, 2)
  pyplot.title("# predicted => inactive cells over window={0}".format(window))
  plotMovingAverage(numPredictedInactiveCells, window)

  pyplot.subplot(3, 1, 3)
  pyplot.title("# unpredicted => active cells over window={0}".format(window))
  plotMovingAverage(numUnpredictedActiveColumns, window)

def plotTraces(tm, timestamp=int(time.time()), window=500):
  """
  Have to make the following change in NuPIC for this to work:

  --- a/nupic/research/TP_shim.py
  +++ b/nupic/research/TP_shim.py
  @@ -27,10 +27,13 @@ for use with OPF.
   import numpy

   from nupic.research.temporal_memory import TemporalMemory
  +from nupic.research.monitor_mixin.temporal_memory_monitor_mixin import (
  +  TemporalMemoryMonitorMixin)
  +class MonitoredTemporalMemory(TemporalMemoryMonitorMixin, TemporalMemory): pass

  -class TPShim(TemporalMemory):
  +class TPShim(MonitoredTemporalMemory):
  """
  traces = tm.mmGetDefaultTraces()
  traces = [trace for trace in traces if type(trace) is CountsTrace]

  t = len(traces)

  for i in xrange(t):
    trace = traces[i]
    pyplot.subplot(t, 1, i+1)
    pyplot.title(trace.title)
    pyplot.xlim(max(len(trace.data)-window, 0), len(trace.data))
    pyplot.plot(range(len(trace.data)), trace.data)

  pyplot.draw()
  # pyplot.savefig("tm-{0}.png".format(timestamp))

if __name__ == "__main__":
  model = ModelFactory.create(MODEL_PARAMS)
  model.enableInference({"predictedField": "element"})
  shifter = InferenceShifter()

  sequences = generateSequences()
  correct = []
  numPredictedActiveCells = []
  numPredictedInactiveCells = []
  numUnpredictedActiveColumns = []

  pyplot.ion()
  pyplot.show()

  from pylab import rcParams

  rcParams.update({'figure.autolayout': True})
  rcParams.update({'figure.facecolor': 'white'})
  rcParams.update({'ytick.labelsize': 8})

  for i in xrange(100000000):
    sequence = random.choice(sequences)

    for j, element in enumerate(sequence):
      result = shifter.shift(model.run({"element": element}))
      # print element, result.inferences["multiStepPredictions"][1]
      tm = model._getTPRegion().getSelf()._tfdr

      if j == len(sequence) - 2:
        tm.mmClearHistory()

      if j == len(sequence) - 1:
        bestPredictions = sorted(result.inferences["multiStepPredictions"][1].items(),
                                 key=operator.itemgetter(1),
                                 reverse=True)
        topPredictions = [int(round(a)) for a, b in bestPredictions[:NUM_PREDICTIONS]]

        print "Evaluation:", element, topPredictions, element in topPredictions

        correct.append(element in topPredictions)
        numPredictedActiveCells.append(len(tm.mmGetTracePredictedActiveCells().data[0]))
        numPredictedInactiveCells.append(len(tm.mmGetTracePredictedInactiveCells().data[0]))
        numUnpredictedActiveColumns.append(len(tm.mmGetTraceUnpredictedActiveColumns().data[0]))

        if i % 100 == 0:
          rcParams.update({'figure.figsize': (12, 6)})
          pyplot.figure(1)
          pyplot.clf()
          plotAccuracy(correct)
          pyplot.draw()

          # rcParams.update({'figure.figsize': (6, 12)})
          # pyplot.figure(2)
          # pyplot.clf()
          # tm = model._getTPRegion().getSelf()._tfdr
          # plotTraces(tm)

          pyplot.figure(2)
          pyplot.clf()
          plotTMStats(numPredictedActiveCells, numPredictedInactiveCells, numUnpredictedActiveColumns)
          pyplot.draw()

    model.resetSequenceStates()
<|endoftext|>


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

from sqlalchemy import Column
from sqlalchemy.dialects import postgresql
from geoalchemy2 import Geometry

from ..extensions import db

class Execucao(db.Model):

    __tablename__ = 'execucao'

    id = Column(db.Integer, primary_key=True)
    # code = Column(db.String(50), nullable=False)
    data = Column(postgresql.JSONB)
    point = Column(Geometry('POINT'))
    searched = Column(db.Boolean, default=False)
<commit_msg>region table<commit_after># -*- coding: utf-8 -*-

from sqlalchemy import Column
from sqlalchemy.dialects import postgresql
from geoalchemy2 import Geometry

from ..extensions import db

class Execucao(db.Model):

    __tablename__ = 'execucao'

    id = Column(db.Integer, primary_key=True)
    # code = Column(db.String(50), nullable=False)
    data = Column(postgresql.JSONB)
    point = Column(Geometry('POINT'))
    searched = Column(db.Boolean, default=False)

    @staticmethod
    def get_region(point):
        """Returns the region of a point."""
        pass

class Regions(db.Model):

    __tablename__ = 'regions'

    id = Column(db.Integer, primary_key=True)
    name = Column(db.String)
    geo = Column(Geometry('POLYGON'))

    @staticmethod
    def get_points(region):
        """Returns the points inside a region."""
        pass
<|endoftext|>


<commit_before>from __future__ import (division, print_function, absolute_import)

from argparse import ArgumentParser
import os
import re
import tarfile
import tempfile
import shutil
import StringIO

import requests

from ruamel import yaml

from conda import config
from conda_build.api import skeletonize

from six.moves import xmlrpc_client as xmlrpclib

from jinja2 import Environment, FileSystemLoader, Template
from jinja2.exceptions import TemplateNotFound

PYPI_XMLRPC = 'https://pypi.python.org/pypi'
TEMPLATE_FOLDER = 'recipe_templates'
RECIPE_FOLDER = 'recipes'
ALL_PLATFORMS = ['osx-64', 'linux-64', 'linux-32', 'win-32', 'win-64']

CONDA_FORGE_FEEDSTOCK_TARBALL = ('https://github.com/conda-forge/{}-feedstock'
                                 '/archive/master.tar.gz')

def get_pypi_info(name):
    client = xmlrpclib.ServerProxy(PYPI_XMLRPC, allow_none=True)
    pypi_stable = client.package_releases(name)
    try:
        return pypi_stable[0]
    except IndexError:
        return None

class Package(object):
    """
    A package to be built for conda.

    Parameters
    ----------

    pypi_name : str
        Name of the package on PyPI. Note that PyPI is not case sensitive.

    version: str, optional
        Version number of the package. ``None``, the default, implies the most
        recent version visible on PyPI should be used.
    """

    # The class should only need one client for communicating with PyPI
    client = xmlrpclib.ServerProxy(PYPI_XMLRPC, allow_none=True)

    def __init__(self, pypi_name, version=None,
                 numpy_compiled_extensions=False,
                 setup_options=None,
                 python_requirements=None,
                 numpy_requirements=None,
                 excluded_platforms=None,
                 include_extras=False):
        self._pypi_name = pypi_name
        self.required_version = version
        self._build = False
        self._url = None
        self._md5 = None
        self._build_platforms = None
        self._extra_meta = None
        self._build_pythons = None
        self._numpy_compiled_extensions = numpy_compiled_extensions
        self._setup_options = setup_options
        self._python_requirements = python_requirements
        self._numpy_requirements = numpy_requirements
        self._excluded_platforms = excluded_platforms or []
        self._include_extras = include_extras

    @property
    def pypi_name(self):
        """
        Name of the package on PyPI.
        """
        return self._pypi_name

    @property
    def conda_name(self):
        """
        Name of the package on binstar (conda), which requires lowercase
        names.
        """
        return self.pypi_name.lower()

    @property
    def required_version(self):
        """
        Version number of the package.
        """
        return self._required_version

    @required_version.setter
    def required_version(self, value):
        if value is not None:
            self._required_version = str(value).strip()
        else:
            self._required_version = value

    @property
    def build(self):
        """
        bool:
            ``True`` if this package needs to be built.
        """
        return self._build

    @build.setter
    def build(self, value):
        # TODO: Make sure this is a bool
        self._build = value

    @property
    def numpy_compiled_extensions(self):
        return self._numpy_compiled_extensions

    @property
    def setup_options(self):
        return self._setup_options

    @property
    def python_requirements(self):
        return self._python_requirements

    @property
    def numpy_requirements(self):
        return self._numpy_requirements

    @property
    def include_extras(self):
        return self._include_extras

    @property
    def is_dev(self):
        return not (re.search('[a-zA-Z]', self.required_version) is None)

    @property
    def url(self):
        if not self._url:
            self._retrieve_package_metadata()

        return self._url

    @property
    def md5(self):
        if not self._md5:
            self._retrieve_package_metadata()

        return self._md5

    @property
    def filename(self):
        return self.url.split('/')[-1]

    @property
    def build_platforms(self):
        """
        Return list of platforms on which this package can be built.

        Defaults to the value of ``ALL_PLATFORMS``.

        Checks for build information by looking at recipe *templates*, which
        is probably not really the way to go...might be more generalizable if
        it looked at recipes instead.

        Also excludes any platforms indicated in requirements.yml,
        """
        # Lazy memoization...
        if self._build_platforms:
            return self._build_platforms

        platform_info = self.extra_meta

        try:
            platforms = platform_info['extra']['platforms']
        except KeyError:
            platforms = ALL_PLATFORMS

        platforms = list(set(platforms) - set(self._excluded_platforms))

        self._build_platforms = platforms
        return self._build_platforms

    @property
    def build_pythons(self):
        if self._build_pythons:
            return self._build_pythons
        try:
            pythons = self.extra_meta['extra']['pythons']
        except KeyError:
            pythons = ["27", "35"]

        # Make sure version is always a string so it can be compared
        # to CONDA_PY later.
        self._build_pythons = [str(p) for p in pythons]
        return self._build_pythons

    @property
    def extra_meta(self):
        """
        The 'extra' metadata, for now read in from meta.yaml.
        """
        if self._extra_meta is not None:
            return self._extra_meta

        try:
            meta = render_template(self, 'meta.yaml')
        except TemplateNotFound:
            # No recipe, make an empty meta for now.
            meta = ''

        platform_info = yaml.safe_load(meta) if meta else {}
        self._extra_meta = platform_info

        return self._extra_meta

    def _retrieve_package_metadata(self):
        """
        Get URL and md5 checksum from PyPI for either the specified version
        or the most recent version.
        """
        if not self.required_version:
            version = get_pypi_info(self.pypi_name)
        else:
            version = self.required_version

        urls = self.client.release_urls(self.pypi_name, version)
        try:
            # Many packages now have wheels, need to iterate over download
            # URLs to get the source distribution.
            for a_url in urls:
                if a_url['packagetype'] == 'sdist':
                    url = a_url['url']
                    md5sum = a_url['md5_digest']
                    break
            else:
                # No source distribution, so raise an index error
                raise IndexError
        except IndexError:
            # Apparently a pypi release isn't required to have any source?
            # If it doesn't, then return None
            print('No source found for {}: {}'.format(self.pypi_name,
                  self.required_version))
            url = None
            md5sum = None
        self._url = url
        self._md5 = md5sum

    @property
    def supported_platform(self):
        """
        True if the current build platform is supported by the package, False
        otherwise.
        """
        return config.subdir in self.build_platforms

def get_package_versions(requirements_path):
    """
    Read and parse list of packages.

    Parameters
    ----------

    requirements_path : str
        Path to ``requirements.yml``

    Returns
    -------

    list
        List of ``Package`` objects, one for each in the requirements file.
    """
    with open(requirements_path, 'rt') as f:
        package_list = yaml.safe_load(f)

    packages = []
    for p in package_list:
        helpers = p.get('setup_options', None)
        numpy_extensions = p.get('numpy_compiled_extensions', False)
        python_requirements = p.get('python', [])
        numpy_requirements = p.get('numpy_build_restrictions', [])
        version = p.get('version', None)
        excluded_platforms = p.get('excluded_platforms', [])
        include_extras = p.get('include_extras', False)

        # TODO: Get supported platforms from requirements,
        #       not from recipe template.
        packages.append(Package(p['name'],
                                version=version,
                                setup_options=helpers,
                                numpy_compiled_extensions=numpy_extensions,
                                python_requirements=python_requirements,
                                numpy_requirements=numpy_requirements,
                                excluded_platforms=excluded_platforms,
                                include_extras=include_extras))

    return packages

def render_template(package, template, folder=TEMPLATE_FOLDER):
    """
    Render recipe components from jinja2 templates.

    Parameters
    ----------

    package : Package
        :class:`Package` object for which template will be rendered.
    template : str
        Name of template file, path relative to ``folder``.
    folder : str
        Path to folder containing template.
    """
    full_template_path = os.path.abspath(folder)
    jinja_env = Environment(loader=FileSystemLoader(full_template_path))
    tpl = jinja_env.get_template('/'.join([package.conda_name, template]))
    rendered = tpl.render(version=package.required_version, md5=package.md5)
    return rendered

def generate_skeleton(package, path):
    """
    Use conda skeleton pypi to generate a recipe for a package and
    save it to path.

    Parameters
    ----------

    package: Package
        The package for which a recipe is to be generated.

    path: str
        Path to which the recipe should be written.
    """

    additional_arguments = ['--version', str(package.required_version),
                            '--output-dir', path]
    additional_arguments = {}
    if package.include_extras:
        additional_arguments['all_extras'] = True

    # Options below ensure an egg is not included in the built package
    additional_arguments['setup_options'] = [
        '--single-version-externally-managed',
        '--record rec.txt'
    ]

    if package.setup_options:
        additional_arguments['setup_options'].append(package.setup_options)

    if package.numpy_compiled_extensions:
        additional_arguments['pin_numpy'] = True

    skeletonize(package.pypi_name, 'pypi',
                output_dir=path,
                version=str(package.required_version),
                **additional_arguments)

def get_conda_forge_recipe(package):
    """
    Get recipe from conda-forge and move it to the appropriate directory.
    """
    feedstock_url = CONDA_FORGE_FEEDSTOCK_TARBALL.format(package.conda_name)
    tarball_raw = requests.get(feedstock_url)

    # Raise an exception if the tarball does not exist.
    tarball_raw.raise_for_status()

    tmp_dir = tempfile.mkdtemp()

    tarball_stream = StringIO.StringIO(str(tarball_raw.content))

    tarball = tarfile.open(fileobj=tarball_stream, mode='r:gz')
    tarball.extractall(tmp_dir)

    for mem in tarball.getmembers():
        if mem.name.endswith('recipe'):
            recipe_src_dir = os.path.join(tmp_dir, mem.name)
            break

    shutil.move(recipe_src_dir,
                os.path.join(RECIPE_FOLDER, package.conda_name))

    shutil.rmtree(tmp_dir)

def inject_requirements(package, recipe_path):
    """
    Two packages get special treatment so that restrictions on build versions,
    which may be more restrictive than the requirements of the package itself.

    Those two packages are python and numpy.
    """
    meta_path = os.path.join(recipe_path, 'meta.yaml')
    with open(meta_path) as f:
        recipe = yaml.load(f, yaml.RoundTripLoader)

    spec = []
    if package.python_requirements:
        spec.append(' '.join(['python', package.python_requirements]))
    if package.numpy_requirements:
        spec.append(' '.join(['numpy', package.numpy_requirements]))

    if spec:
        for section in ['build', 'run']:
            recipe['requirements'][section].extend(spec)

    with open(meta_path, 'w') as f:
        yaml.dump(recipe, f, Dumper=yaml.RoundTripDumper,
                  default_flow_style=False)

def main(args=None):
    """
    Generate recipes for packages either from recipe templates, by copying
    from conda-forge, or by using conda skeleton.
    """
    if args is None:
        parser = ArgumentParser('command line tool for building packages.')
        parser.add_argument('requirements',
                            help='Path to requirements.yml')
        parser.add_argument('--template-dir', default=TEMPLATE_FOLDER,
                            help="Path the folder of recipe templates, if "
                                 "any. Default: '{}'".format(TEMPLATE_FOLDER))
        args = parser.parse_args()
        template_dir = args.template_dir

    packages = get_package_versions(args.requirements)

    packages = [p for p in packages if p.supported_platform]

    try:
        needs_recipe = os.listdir(template_dir)
    except OSError:
        needs_recipe = []

    build_recipe = [p for p in packages if p.conda_name in needs_recipe]
    build_not_recipe = [p for p in packages if p.conda_name not in needs_recipe]

    if build_recipe or build_not_recipe:
        os.mkdir(RECIPE_FOLDER)

    # Write recipes from templates.
    for p in build_recipe:
        print('Writing recipe for {}.'.format(p.conda_name))
        recipe_path = os.path.join(RECIPE_FOLDER, p.conda_name)
        template_path = os.path.join(template_dir, p.conda_name)
        os.mkdir(recipe_path)
        templates = [d for d in os.listdir(template_path) if
                     not d.startswith('.')]
        for template in templates:
            rendered = render_template(p, template, folder=template_dir)
            with open(os.path.join(recipe_path, template), 'wt') as f:
                f.write(rendered)
        inject_requirements(p, recipe_path)

    # check conda-forge for a recipe, and if it is not found, add to the skeleton
    # list.
    build_skeleton = []
    for p in build_not_recipe:
        # Try grabbing the recipe from conda-forge
        try:
            get_conda_forge_recipe(p)
        except requests.HTTPError:
            build_skeleton.append(p)
            continue

        recipe_path = os.path.join(RECIPE_FOLDER, p.conda_name)
        meta_path = os.path.join(recipe_path, 'meta.yaml')
        print("Pulled recipe from conda-forge for {}".format(p.conda_name))
        with open(meta_path) as f:
            recipe_meta = f.read()

        # Check the version number of the recipe and perhaps modify it
        version_from_recipe = re.search('version = "(.*)"', recipe_meta)
        if not version_from_recipe:
            # Try looking for the recipe in the yaml instead of
            # a jinja variable.
            version_from_recipe = re.search('^\s+version: (\d.*)$',
                                            recipe_meta)

        version_from_recipe = version_from_recipe.group(1)

        print("recipe version: {}\nrequirements version: {}".format(version_from_recipe, p.required_version))
        if p.required_version:
            assert p.required_version == version_from_recipe

    # Use conda skeleton to generate recipes for the simple cases
    for p in build_skeleton:
        print('generating skeleton for {}'.format(p.conda_name))
        recipe_destination = os.path.join(RECIPE_FOLDER, p.conda_name)
        generate_skeleton(p, RECIPE_FOLDER)

        inject_requirements(p, recipe_destination)

if __name__ == '__main__':
    main()
<commit_msg>Use BytesIO instead of StringIO<commit_after>from __future__ import (division, print_function, absolute_import)

from argparse import ArgumentParser
import os
import re
import tarfile
import tempfile
import shutil
import io

import requests

from ruamel import yaml

from conda import config
from conda_build.api import skeletonize

from six.moves import xmlrpc_client as xmlrpclib

from jinja2 import Environment, FileSystemLoader, Template
from jinja2.exceptions import TemplateNotFound

PYPI_XMLRPC = 'https://pypi.python.org/pypi'
TEMPLATE_FOLDER = 'recipe_templates'
RECIPE_FOLDER = 'recipes'
ALL_PLATFORMS = ['osx-64', 'linux-64', 'linux-32', 'win-32', 'win-64']

CONDA_FORGE_FEEDSTOCK_TARBALL = ('https://github.com/conda-forge/{}-feedstock'
                                 '/archive/master.tar.gz')

def get_pypi_info(name):
    client = xmlrpclib.ServerProxy(PYPI_XMLRPC, allow_none=True)
    pypi_stable = client.package_releases(name)
    try:
        return pypi_stable[0]
    except IndexError:
        return None

class Package(object):
    """
    A package to be built for conda.

    Parameters
    ----------

    pypi_name : str
        Name of the package on PyPI. Note that PyPI is not case sensitive.

    version: str, optional
        Version number of the package. ``None``, the default, implies the most
        recent version visible on PyPI should be used.
    """

    # The class should only need one client for communicating with PyPI
    client = xmlrpclib.ServerProxy(PYPI_XMLRPC, allow_none=True)

    def __init__(self, pypi_name, version=None,
                 numpy_compiled_extensions=False,
                 setup_options=None,
                 python_requirements=None,
                 numpy_requirements=None,
                 excluded_platforms=None,
                 include_extras=False):
        self._pypi_name = pypi_name
        self.required_version = version
        self._build = False
        self._url = None
        self._md5 = None
        self._build_platforms = None
        self._extra_meta = None
        self._build_pythons = None
        self._numpy_compiled_extensions = numpy_compiled_extensions
        self._setup_options = setup_options
        self._python_requirements = python_requirements
        self._numpy_requirements = numpy_requirements
        self._excluded_platforms = excluded_platforms or []
        self._include_extras = include_extras

    @property
    def pypi_name(self):
        """
        Name of the package on PyPI.
        """
        return self._pypi_name

    @property
    def conda_name(self):
        """
        Name of the package on binstar (conda), which requires lowercase
        names.
        """
        return self.pypi_name.lower()

    @property
    def required_version(self):
        """
        Version number of the package.
        """
        return self._required_version

    @required_version.setter
    def required_version(self, value):
        if value is not None:
            self._required_version = str(value).strip()
        else:
            self._required_version = value

    @property
    def build(self):
        """
        bool:
            ``True`` if this package needs to be built.
        """
        return self._build

    @build.setter
    def build(self, value):
        # TODO: Make sure this is a bool
        self._build = value

    @property
    def numpy_compiled_extensions(self):
        return self._numpy_compiled_extensions

    @property
    def setup_options(self):
        return self._setup_options

    @property
    def python_requirements(self):
        return self._python_requirements

    @property
    def numpy_requirements(self):
        return self._numpy_requirements

    @property
    def include_extras(self):
        return self._include_extras

    @property
    def is_dev(self):
        return not (re.search('[a-zA-Z]', self.required_version) is None)

    @property
    def url(self):
        if not self._url:
            self._retrieve_package_metadata()

        return self._url

    @property
    def md5(self):
        if not self._md5:
            self._retrieve_package_metadata()

        return self._md5

    @property
    def filename(self):
        return self.url.split('/')[-1]

    @property
    def build_platforms(self):
        """
        Return list of platforms on which this package can be built.

        Defaults to the value of ``ALL_PLATFORMS``.

        Checks for build information by looking at recipe *templates*, which
        is probably not really the way to go...might be more generalizable if
        it looked at recipes instead.

        Also excludes any platforms indicated in requirements.yml,
        """
        # Lazy memoization...
        if self._build_platforms:
            return self._build_platforms

        platform_info = self.extra_meta

        try:
            platforms = platform_info['extra']['platforms']
        except KeyError:
            platforms = ALL_PLATFORMS

        platforms = list(set(platforms) - set(self._excluded_platforms))

        self._build_platforms = platforms
        return self._build_platforms

    @property
    def build_pythons(self):
        if self._build_pythons:
            return self._build_pythons
        try:
            pythons = self.extra_meta['extra']['pythons']
        except KeyError:
            pythons = ["27", "35"]

        # Make sure version is always a string so it can be compared
        # to CONDA_PY later.
        self._build_pythons = [str(p) for p in pythons]
        return self._build_pythons

    @property
    def extra_meta(self):
        """
        The 'extra' metadata, for now read in from meta.yaml.
        """
        if self._extra_meta is not None:
            return self._extra_meta

        try:
            meta = render_template(self, 'meta.yaml')
        except TemplateNotFound:
            # No recipe, make an empty meta for now.
            meta = ''

        platform_info = yaml.safe_load(meta) if meta else {}
        self._extra_meta = platform_info

        return self._extra_meta

    def _retrieve_package_metadata(self):
        """
        Get URL and md5 checksum from PyPI for either the specified version
        or the most recent version.
        """
        if not self.required_version:
            version = get_pypi_info(self.pypi_name)
        else:
            version = self.required_version

        urls = self.client.release_urls(self.pypi_name, version)
        try:
            # Many packages now have wheels, need to iterate over download
            # URLs to get the source distribution.
            for a_url in urls:
                if a_url['packagetype'] == 'sdist':
                    url = a_url['url']
                    md5sum = a_url['md5_digest']
                    break
            else:
                # No source distribution, so raise an index error
                raise IndexError
        except IndexError:
            # Apparently a pypi release isn't required to have any source?
            # If it doesn't, then return None
            print('No source found for {}: {}'.format(self.pypi_name,
                  self.required_version))
            url = None
            md5sum = None
        self._url = url
        self._md5 = md5sum

    @property
    def supported_platform(self):
        """
        True if the current build platform is supported by the package, False
        otherwise.
        """
        return config.subdir in self.build_platforms

def get_package_versions(requirements_path):
    """
    Read and parse list of packages.

    Parameters
    ----------

    requirements_path : str
        Path to ``requirements.yml``

    Returns
    -------

    list
        List of ``Package`` objects, one for each in the requirements file.
    """
    with open(requirements_path, 'rt') as f:
        package_list = yaml.safe_load(f)

    packages = []
    for p in package_list:
        helpers = p.get('setup_options', None)
        numpy_extensions = p.get('numpy_compiled_extensions', False)
        python_requirements = p.get('python', [])
        numpy_requirements = p.get('numpy_build_restrictions', [])
        version = p.get('version', None)
        excluded_platforms = p.get('excluded_platforms', [])
        include_extras = p.get('include_extras', False)

        # TODO: Get supported platforms from requirements,
        #       not from recipe template.
        packages.append(Package(p['name'],
                                version=version,
                                setup_options=helpers,
                                numpy_compiled_extensions=numpy_extensions,
                                python_requirements=python_requirements,
                                numpy_requirements=numpy_requirements,
                                excluded_platforms=excluded_platforms,
                                include_extras=include_extras))

    return packages

def render_template(package, template, folder=TEMPLATE_FOLDER):
    """
    Render recipe components from jinja2 templates.

    Parameters
    ----------

    package : Package
        :class:`Package` object for which template will be rendered.
    template : str
        Name of template file, path relative to ``folder``.
    folder : str
        Path to folder containing template.
    """
    full_template_path = os.path.abspath(folder)
    jinja_env = Environment(loader=FileSystemLoader(full_template_path))
    tpl = jinja_env.get_template('/'.join([package.conda_name, template]))
    rendered = tpl.render(version=package.required_version, md5=package.md5)
    return rendered

def generate_skeleton(package, path):
    """
    Use conda skeleton pypi to generate a recipe for a package and
    save it to path.

    Parameters
    ----------

    package: Package
        The package for which a recipe is to be generated.

    path: str
        Path to which the recipe should be written.
    """

    additional_arguments = ['--version', str(package.required_version),
                            '--output-dir', path]
    additional_arguments = {}
    if package.include_extras:
        additional_arguments['all_extras'] = True

    # Options below ensure an egg is not included in the built package
    additional_arguments['setup_options'] = [
        '--single-version-externally-managed',
        '--record rec.txt'
    ]

    if package.setup_options:
        additional_arguments['setup_options'].append(package.setup_options)

    if package.numpy_compiled_extensions:
        additional_arguments['pin_numpy'] = True

    skeletonize(package.pypi_name, 'pypi',
                output_dir=path,
                version=str(package.required_version),
                **additional_arguments)

def get_conda_forge_recipe(package):
    """
    Get recipe from conda-forge and move it to the appropriate directory.
    """
    feedstock_url = CONDA_FORGE_FEEDSTOCK_TARBALL.format(package.conda_name)
    tarball_raw = requests.get(feedstock_url)

    # Raise an exception if the tarball does not exist.
    tarball_raw.raise_for_status()

    tmp_dir = tempfile.mkdtemp()

    tarball_stream = io.BytesIO(tarball_raw.content)

    tarball = tarfile.open(fileobj=tarball_stream, mode='r:gz')
    tarball.extractall(tmp_dir)

    for mem in tarball.getmembers():
        if mem.name.endswith('recipe'):
            recipe_src_dir = os.path.join(tmp_dir, mem.name)
            break

    shutil.move(recipe_src_dir,
                os.path.join(RECIPE_FOLDER, package.conda_name))

    shutil.rmtree(tmp_dir)

def inject_requirements(package, recipe_path):
    """
    Two packages get special treatment so that restrictions on build versions,
    which may be more restrictive than the requirements of the package itself.

    Those two packages are python and numpy.
    """
    meta_path = os.path.join(recipe_path, 'meta.yaml')
    with open(meta_path) as f:
        recipe = yaml.load(f, yaml.RoundTripLoader)

    spec = []
    if package.python_requirements:
        spec.append(' '.join(['python', package.python_requirements]))
    if package.numpy_requirements:
        spec.append(' '.join(['numpy', package.numpy_requirements]))

    if spec:
        for section in ['build', 'run']:
            recipe['requirements'][section].extend(spec)

    with open(meta_path, 'w') as f:
        yaml.dump(recipe, f, Dumper=yaml.RoundTripDumper,
                  default_flow_style=False)

def main(args=None):
    """
    Generate recipes for packages either from recipe templates, by copying
    from conda-forge, or by using conda skeleton.
    """
    if args is None:
        parser = ArgumentParser('command line tool for building packages.')
        parser.add_argument('requirements',
                            help='Path to requirements.yml')
        parser.add_argument('--template-dir', default=TEMPLATE_FOLDER,
                            help="Path the folder of recipe templates, if "
                                 "any. Default: '{}'".format(TEMPLATE_FOLDER))
        args = parser.parse_args()
        template_dir = args.template_dir

    packages = get_package_versions(args.requirements)

    packages = [p for p in packages if p.supported_platform]

    try:
        needs_recipe = os.listdir(template_dir)
    except OSError:
        needs_recipe = []

    build_recipe = [p for p in packages if p.conda_name in needs_recipe]
    build_not_recipe = [p for p in packages if p.conda_name not in needs_recipe]

    if build_recipe or build_not_recipe:
        os.mkdir(RECIPE_FOLDER)

    # Write recipes from templates.
    for p in build_recipe:
        print('Writing recipe for {}.'.format(p.conda_name))
        recipe_path = os.path.join(RECIPE_FOLDER, p.conda_name)
        template_path = os.path.join(template_dir, p.conda_name)
        os.mkdir(recipe_path)
        templates = [d for d in os.listdir(template_path) if
                     not d.startswith('.')]
        for template in templates:
            rendered = render_template(p, template, folder=template_dir)
            with open(os.path.join(recipe_path, template), 'wt') as f:
                f.write(rendered)
        inject_requirements(p, recipe_path)

    # check conda-forge for a recipe, and if it is not found, add to the skeleton
    # list.
    build_skeleton = []
    for p in build_not_recipe:
        # Try grabbing the recipe from conda-forge
        try:
            get_conda_forge_recipe(p)
        except requests.HTTPError:
            build_skeleton.append(p)
            continue

        recipe_path = os.path.join(RECIPE_FOLDER, p.conda_name)
        meta_path = os.path.join(recipe_path, 'meta.yaml')
        print("Pulled recipe from conda-forge for {}".format(p.conda_name))
        with open(meta_path) as f:
            recipe_meta = f.read()

        # Check the version number of the recipe and perhaps modify it
        version_from_recipe = re.search('version = "(.*)"', recipe_meta)
        if not version_from_recipe:
            # Try looking for the recipe in the yaml instead of
            # a jinja variable.
            version_from_recipe = re.search('^\s+version: (\d.*)$',
                                            recipe_meta)

        version_from_recipe = version_from_recipe.group(1)

        print("recipe version: {}\nrequirements version: {}".format(version_from_recipe, p.required_version))
        if p.required_version:
            assert p.required_version == version_from_recipe

    # Use conda skeleton to generate recipes for the simple cases
    for p in build_skeleton:
        print('generating skeleton for {}'.format(p.conda_name))
        recipe_destination = os.path.join(RECIPE_FOLDER, p.conda_name)
        generate_skeleton(p, RECIPE_FOLDER)

        inject_requirements(p, recipe_destination)

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


<commit_before>"""Command-line interface for Zellij."""

import pprint
import re

import click

from zellij.color import random_color
from zellij.design import get_design
from zellij.drawing import Drawing
from zellij.path_tiler import combine_paths, replay_path, PathTiler
from zellij.strap import strapify

def size_type(s):
    """For specifying the size: either WxH, or W (square)"""
    if 'x' in s:
        width, height = s.split('x')
    else:
        width = height = s

    return int(width.strip()), int(height.strip())

DEBUGS = ['opts', 'world']

def debug_type(s):
    # I am certain there's a better way to get click to do this...
    debugs = [sp.strip() for sp in re.split(r"[ ,;]+", s)]
    for d in debugs:
        if d not in DEBUGS:
            raise click.BadOptionUsage(f"--debug={d}??")
    return debugs

_common_options = {
    'common':[
        click.option('--debug', type=debug_type),
    ],
    'drawing': [
        click.option('--output', default='drawing.png', help='File name to write to'),
        click.option('--tiles', type=float, default=3, help='How many tiles to fit in the drawing'),
        click.option('--size', type=size_type, default='800', help='Size of the output'),
        click.option('--format', default='png'),
        click.argument('design'),
    ],
}

def common_options(category):
    def _wrapper(func):
        # from: https://github.com/pallets/click/issues/108#issuecomment-194465429
        for option in reversed(_common_options[category]):
            func = option(func)
        return func
    return _wrapper

@click.group()
def clickmain():
    pass

def debug_world(paths, width, height):
    dwg = Drawing(paths=paths, name="debug_world")
    with dwg.style(rgb=(.95, .95, .95)):
        dwg.rectangle(0, 0, width, height)
        dwg.fill()
    dwg.draw_paths(paths, width=1, rgb=(1, 0, 0))
    dwg.finish()
    print("Wrote debug_world.png")

@clickmain.command()
@common_options('common')
@common_options('drawing')
@click.option("--strap-width", type=float, default=6, help='Width of the straps, in tile-percent')
def straps(**opt):
    width, height = opt['size']

    TILEW = int(width/opt['tiles'])
    if opt['strap_width'] > 0:
        strap_kwargs = dict(width=TILEW * opt['strap_width'] / 100, random_factor=0)
    else:
        strap_kwargs = dict(width=TILEW / 60, random_factor=4.9)

    dwg = Drawing(width, height, name="straps", bg=(.8, .8, .8))
    pt = PathTiler()
    design_class = get_design(opt['design'])
    draw = design_class(TILEW)
    draw.draw(pt, dwg.get_size())
    paths = combine_paths(pt.paths)

    if 'world' in opt['debug']:
        debug_world(paths, width, height)

    straps = strapify(paths, **strap_kwargs)

    with dwg.style(rgb=(1, 1, 1)):
        for strap in straps:
            replay_path(strap.sides[0], dwg)
            replay_path(strap.sides[1][::-1], dwg, append=True)
            dwg.close_path()
            dwg.fill()

    with dwg.style(rgb=(0, 0, 0), width=2):
        for strap in straps:
            for side in strap.sides:
                replay_path(side, dwg)
                dwg.stroke()

    dwg.finish()

@clickmain.command()
@common_options('common')
@common_options('drawing')
def candystripe(**opt):
    width, height = opt['size']

    TILEW = int(width/opt['tiles'])

    dwg = Drawing(width, height, name="candy")
    pt = PathTiler()
    design_class = get_design(opt['design'])
    draw = design_class(TILEW)
    draw.draw(pt, dwg.get_size())
    paths = combine_paths(pt.paths)

    LINE_WIDTH = TILEW/4

    dwg.multi_stroke(paths, [
        #(LINE_WIDTH, (0, 0, 0)),
        (LINE_WIDTH-2, random_color),
        #(7, (0, 0, 0)),
        (5, (1, 1, 1)),
    ])
    dwg.finish()

@clickmain.command()
@common_options('common')
@common_options('drawing')
def show_opts(**opt):
    pprint.pprint(opt)

def main():
    # A Python main so we can eventually do some clean top-level exception handling.
    try:
        clickmain()
    except:
        #print("Whoops!")
        raise

if __name__ == '__main__':
    main()
<commit_msg>Fix handling of no --debug<commit_after>"""Command-line interface for Zellij."""

import pprint
import re

import click

from zellij.color import random_color
from zellij.design import get_design
from zellij.drawing import Drawing
from zellij.path_tiler import combine_paths, replay_path, PathTiler
from zellij.strap import strapify

def size_type(s):
    """For specifying the size: either WxH, or W (square)"""
    if 'x' in s:
        width, height = s.split('x')
    else:
        width = height = s

    return int(width.strip()), int(height.strip())

DEBUGS = ['opts', 'world']

def debug_type(s):
    # I am certain there's a better way to get click to do this...
    debugs = [sp.strip() for sp in re.split(r"[ ,;]+", s)]
    debugs = [d for d in debugs if d]
    for d in debugs:
        if d not in DEBUGS:
            raise click.BadOptionUsage(f"--debug={d}?? Choose from {', '.join(DEBUGS)}")
    return debugs

_common_options = {
    'common':[
        click.option('--debug', type=debug_type, default=""),
    ],
    'drawing': [
        click.option('--output', default='drawing.png', help='File name to write to'),
        click.option('--tiles', type=float, default=3, help='How many tiles to fit in the drawing'),
        click.option('--size', type=size_type, default='800', help='Size of the output'),
        click.option('--format', default='png'),
        click.argument('design'),
    ],
}

def common_options(category):
    def _wrapper(func):
        # from: https://github.com/pallets/click/issues/108#issuecomment-194465429
        for option in reversed(_common_options[category]):
            func = option(func)
        return func
    return _wrapper

@click.group()
def clickmain():
    pass

def debug_world(paths, width, height):
    dwg = Drawing(paths=paths, name="debug_world")
    with dwg.style(rgb=(.95, .95, .95)):
        dwg.rectangle(0, 0, width, height)
        dwg.fill()
    dwg.draw_paths(paths, width=1, rgb=(1, 0, 0))
    dwg.finish()
    print("Wrote debug_world.png")

@clickmain.command()
@common_options('common')
@common_options('drawing')
@click.option("--strap-width", type=float, default=6, help='Width of the straps, in tile-percent')
def straps(**opt):
    width, height = opt['size']

    TILEW = int(width/opt['tiles'])
    if opt['strap_width'] > 0:
        strap_kwargs = dict(width=TILEW * opt['strap_width'] / 100, random_factor=0)
    else:
        strap_kwargs = dict(width=TILEW / 60, random_factor=4.9)

    dwg = Drawing(width, height, name="straps", bg=(.8, .8, .8))
    pt = PathTiler()
    design_class = get_design(opt['design'])
    draw = design_class(TILEW)
    draw.draw(pt, dwg.get_size())
    paths = combine_paths(pt.paths)

    if 'world' in opt['debug']:
        debug_world(paths, width, height)

    straps = strapify(paths, **strap_kwargs)

    with dwg.style(rgb=(1, 1, 1)):
        for strap in straps:
            replay_path(strap.sides[0], dwg)
            replay_path(strap.sides[1][::-1], dwg, append=True)
            dwg.close_path()
            dwg.fill()

    with dwg.style(rgb=(0, 0, 0), width=2):
        for strap in straps:
            for side in strap.sides:
                replay_path(side, dwg)
                dwg.stroke()

    dwg.finish()

@clickmain.command()
@common_options('common')
@common_options('drawing')
def candystripe(**opt):
    width, height = opt['size']

    TILEW = int(width/opt['tiles'])

    dwg = Drawing(width, height, name="candy")
    pt = PathTiler()
    design_class = get_design(opt['design'])
    draw = design_class(TILEW)
    draw.draw(pt, dwg.get_size())
    paths = combine_paths(pt.paths)

    LINE_WIDTH = TILEW/4

    dwg.multi_stroke(paths, [
        #(LINE_WIDTH, (0, 0, 0)),
        (LINE_WIDTH-2, random_color),
        #(7, (0, 0, 0)),
        (5, (1, 1, 1)),
    ])
    dwg.finish()

@clickmain.command()
@common_options('common')
@common_options('drawing')
def show_opts(**opt):
    pprint.pprint(opt)

def main():
    # A Python main so we can eventually do some clean top-level exception handling.
    try:
        clickmain()
    except:
        #print("Whoops!")
        raise

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


<commit_before>import six
from datetime import date
import json
import decimal

if six.PY3:
    import urllib.request as urllib
else:
    import urllib2 as urllib

from generic_request_signer import response, factory

def json_encoder(obj):
    if isinstance(obj, date):
        return str(obj.isoformat())
    if isinstance(obj, decimal.Decimal):
        return str(obj)

class Client(object):

    def __init__(self, api_credentials):
        self.api_credentials = api_credentials

    def get_factory(self, files):
        if files:
            return factory.MultipartSignedRequestFactory
        return factory.SignedRequestFactory

    def _get_response(self, http_method, endpoint, data=None, files=None, timeout=15, **request_kwargs):
        headers = request_kwargs.get("headers", {})
        if not isinstance(data, str) and headers.get("Content-Type") == "application/json":
            data = json.dumps(data, default=json_encoder)
        try:
            http_response = urllib.urlopen(
                self._get_request(http_method, endpoint, data, files, **request_kwargs), timeout=timeout)
        except urllib.HTTPError as e:
            http_response = e
        return response.Response(http_response)

    def _get_request(self, http_method, endpoint, data=None, files=None, **request_kwargs):
        factory_class = self.get_factory(files)
        request_factory = factory_class(http_method, self._client_id, self._private_key, data, files)
        service_url = self._get_service_url(endpoint)
        return request_factory.create_request(service_url, **request_kwargs)

    def _get_service_url(self, endpoint):
        return self._base_url + endpoint

    @property
    def _base_url(self):
        return self.api_credentials.base_url

    @property
    def _client_id(self):
        return self.api_credentials.client_id

    @property
    def _private_key(self):
        return self.api_credentials.private_key
<commit_msg>Bug Fix: reimplement sort keys when creating JSON data to send<commit_after>import six
import json
import decimal

try:
    from apysigner import DefaultJSONEncoder
except ImportError:
    from datetime import datetime

    class DefaultJSONEncoder(json.JSONEncoder):
        """
        JSONEncoder subclass that knows how to encode date/time and decimal types.
        """
        def default(self, o):
            if isinstance(o, (datetime.datetime, datetime.date, datetime.time)):
                return o.isoformat()
            elif isinstance(o, decimal.Decimal):
                return str(o)
            else:
                return super(DefaultJSONEncoder, self).default(o)

if six.PY3:
    import urllib.request as urllib
else:
    import urllib2 as urllib

from generic_request_signer import response, factory

class Client(object):

    def __init__(self, api_credentials):
        self.api_credentials = api_credentials

    def get_factory(self, files):
        if files:
            return factory.MultipartSignedRequestFactory
        return factory.SignedRequestFactory

    def _get_response(self, http_method, endpoint, data=None, files=None, timeout=15, **request_kwargs):
        headers = request_kwargs.get("headers", {})
        if not isinstance(data, str) and headers.get("Content-Type") == "application/json":
            data = json.dumps(data, default=DefaultJSONEncoder, sort_keys=True)
        try:
            http_response = urllib.urlopen(
                self._get_request(http_method, endpoint, data, files, **request_kwargs), timeout=timeout)
        except urllib.HTTPError as e:
            http_response = e
        return response.Response(http_response)

    def _get_request(self, http_method, endpoint, data=None, files=None, **request_kwargs):
        factory_class = self.get_factory(files)
        request_factory = factory_class(http_method, self._client_id, self._private_key, data, files)
        service_url = self._get_service_url(endpoint)
        return request_factory.create_request(service_url, **request_kwargs)

    def _get_service_url(self, endpoint):
        return self._base_url + endpoint

    @property
    def _base_url(self):
        return self.api_credentials.base_url

    @property
    def _client_id(self):
        return self.api_credentials.client_id

    @property
    def _private_key(self):
        return self.api_credentials.private_key
<|endoftext|>