<commit_before>#    Copyright 2016-2016 ARM Limited
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
"""Base matplotlib plotter module"""
from abc import abstractmethod, ABCMeta
from collections import defaultdict as ddict
import matplotlib.pyplot as plt
from trappy.plotter import AttrConf
from trappy.plotter.Constraint import ConstraintManager
from trappy.plotter.PlotLayout import PlotLayout
from trappy.plotter.AbstractDataPlotter import AbstractDataPlotter
from trappy.plotter.ColorMap import ColorMap

class StaticPlot(AbstractDataPlotter):
    """
    This class uses :mod:`trappy.plotter.Constraint.Constraint` to
    represent different permutations of input parameters. These
    constraints are generated by creating an instance of
    :mod:`trappy.plotter.Constraint.ConstraintManager`.

    :param trace: The input data
    :type trace: :mod:`trappy.trace.FTrace` or :mod:`pandas.DataFrame`, list or single

    :param column: specifies the name of the column to
           be plotted.
    :type column: (str, list(str))

    :param templates: TRAPpy events

        .. note::

                This is not required if a :mod:`pandas.DataFrame` is
                used

    :type templates: :mod:`trappy.base.Base`

    :param filters: Filter the column to be plotted as per the
        specified criteria. For Example:
        ::

            filters =
                    {
                        "pid": [ 3338 ],
                        "cpu": [0, 2, 4],
                    }
    :type filters: dict

    :param per_line: Used to control the number of graphs
        in each graph subplot row
    :type per_line: int

    :param concat: Draw all the pivots on a single graph
    :type concat: bool

    :param permute: Draw one plot for each of the traces specified
    :type permute: bool

    :param drawstyle: This argument is forwarded to the matplotlib
        corresponding :func:`matplotlib.pyplot.plot` call

        drawing style.

        .. note::

            step plots are not currently supported for filled
            graphs

    :param xlim: A tuple representing the upper and lower xlimits
    :type xlim: tuple

    :param ylim: A tuple representing the upper and lower ylimits
    :type ylim: tuple

    :param title: A title describing all the generated plots
    :type title: str

    :param style: Created pre-styled graphs loaded from
        :mod:`trappy.plotter.AttrConf.MPL_STYLE`
    :type style: bool

    :param signals: A string of the type event_name:column
        to indicate the value that needs to be plotted

        .. note::

            - Only one of `signals` or both `templates` and
              `columns` should be specified
            - Signals format won't work for :mod:`pandas.DataFrame`
              input

    :type signals: str

    :param legend_ncol: A positive integer that represents the
        number of columns in the legend
    :type legend_ncol: int
    """
    __metaclass__ = ABCMeta

    def __init__(self, traces, templates, **kwargs):
        self._fig = None
        self._layout = None
        super(StaticPlot, self).__init__(traces=traces,
                                         templates=templates)

        self.set_defaults()

        for key in kwargs:
            if key in AttrConf.ARGS_TO_FORWARD:
                self._attr["args_to_forward"][key] = kwargs[key]
            else:
                self._attr[key] = kwargs[key]

        if "signals" in self._attr:
            self._describe_signals()

        self._check_data()

        if "column" not in self._attr:
            raise RuntimeError("Value Column not specified")

        zip_constraints = not self._attr["permute"]
        self.c_mgr = ConstraintManager(traces, self._attr["column"],
                                       self.templates, self._attr["pivot"],
                                       self._attr["filters"], zip_constraints)

    def savefig(self, *args, **kwargs):
        """Save the plot as a PNG fill. This calls into
        :mod:`matplotlib.figure.savefig`
        """

        if self._fig is None:
            self.view()
        self._fig.savefig(*args, **kwargs)

    @abstractmethod
    def set_defaults(self):
        """Sets the default attrs"""
        self._attr["width"] = AttrConf.WIDTH
        self._attr["length"] = AttrConf.LENGTH
        self._attr["per_line"] = AttrConf.PER_LINE
        self._attr["concat"] = AttrConf.CONCAT
        self._attr["filters"] = {}
        self._attr["style"] = True
        self._attr["permute"] = False
        self._attr["pivot"] = AttrConf.PIVOT
        self._attr["xlim"] = AttrConf.XLIM
        self._attr["ylim"] = AttrConf.XLIM
        self._attr["title"] = AttrConf.TITLE
        self._attr["args_to_forward"] = {}
        self._attr["map_label"] = {}
        self._attr["_legend_handles"] = []
        self._attr["_legend_labels"] = []
        self._attr["legend_ncol"] = AttrConf.LEGEND_NCOL

    def view(self, test=False):
        """Displays the graph"""

        if test:
            self._attr["style"] = True
            AttrConf.MPL_STYLE["interactive"] = False

        permute = self._attr["permute"] and not self._attr["concat"]
        if self._attr["style"]:
            with plt.rc_context(AttrConf.MPL_STYLE):
                self._resolve(permute, self._attr["concat"])
        else:
            self._resolve(permute, self._attr["concat"])

    def make_title(self, constraint, pivot, permute, concat):
        """Generates a title string for an axis"""
        if concat:
            return str(constraint)

        if permute:
            return constraint.column
        elif pivot != AttrConf.PIVOT_VAL:
            return "{0}: {1}".format(self._attr["pivot"], self._attr["map_label"].get(pivot, pivot))
        else:
            return ""

    def add_to_legend(self, series_index, handle, constraint, pivot, concat, permute):
        """
        Add series handles and names to the legend
        A handle is returned from a plot on an axis
        e.g. Line2D from axis.plot()
        """
        self._attr["_legend_handles"][series_index] = handle
        legend_labels = self._attr["_legend_labels"]

        if concat and pivot == AttrConf.PIVOT_VAL:
            legend_labels[series_index] = self._attr["column"]
        elif concat:
            legend_labels[series_index] = "{0}: {1}".format(
                self._attr["pivot"],
                self._attr["map_label"].get(pivot, pivot)
            )
        elif permute:
            legend_labels[series_index] = constraint.get_data_name() + ":" + constraint._template.name
        else:
            legend_labels[series_index] = str(constraint)

    def _resolve(self, permute, concat):
        """Determine what data to plot on which axis"""
        pivot_vals, len_pivots = self.c_mgr.generate_pivots(permute)
        pivot_vals = list(pivot_vals)

        num_of_axes = len(self.c_mgr) if concat else len_pivots

        # Create a 2D Layout
        self._layout = PlotLayout(
            self._attr["per_line"],
            num_of_axes,
            width=self._attr["width"],
            length=self._attr["length"],
            title=self._attr['title'])

        self._fig = self._layout.get_fig()

        #Determine what constraint to plot and the corresponding pivot value
        if permute:
            legend_len = self.c_mgr._max_len
            pivots = [y for _, y in pivot_vals]
            cp_pairs = [(c, p) for c in self.c_mgr for p in sorted(set(pivots))]
        else:
            legend_len = len_pivots if concat else len(self.c_mgr)
            pivots = pivot_vals
            cp_pairs = [(c, p) for c in self.c_mgr for p in pivots if p in c.result]

        #Initialise legend data and colormap
        self._attr["_legend_handles"] = [None] * legend_len
        self._attr["_legend_labels"] = [None] * legend_len
        self._cmap = ColorMap(legend_len)

        #Group constraints/series with the axis they are to be plotted on
        figure_data = ddict(list)
        for i, (constraint, pivot) in enumerate(cp_pairs):
            axis = self._layout.get_axis(constraint.trace_index if concat else i)
            figure_data[axis].append((constraint, pivot))

        #Plot each axis
        for axis, series_list in figure_data.iteritems():
            self.plot_axis(
                axis,
                series_list,
                permute,
                self._attr["concat"],
                self._attr["args_to_forward"]
            )

        self._fig.legend(self._attr["_legend_handles"],
                         self._attr["_legend_labels"],
                         loc='lower center',
                         ncol=self._attr["legend_ncol"],
                         borderaxespad=0.)

        self._layout.finish(num_of_axes)

    def plot_axis(self, axis, series_list, permute, concat, args_to_forward):
        """Internal Method called to plot data (series_list) on a given axis"""
        raise NotImplementedError("Method Not Implemented")
<commit_msg>plotter: StaticPlot: fix data plotted when selecting permute option<commit_after>#    Copyright 2016-2016 ARM Limited
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
"""Base matplotlib plotter module"""
from abc import abstractmethod, ABCMeta
from collections import defaultdict as ddict
import matplotlib.pyplot as plt
from trappy.plotter import AttrConf
from trappy.plotter.Constraint import ConstraintManager
from trappy.plotter.PlotLayout import PlotLayout
from trappy.plotter.AbstractDataPlotter import AbstractDataPlotter
from trappy.plotter.ColorMap import ColorMap

class StaticPlot(AbstractDataPlotter):
    """
    This class uses :mod:`trappy.plotter.Constraint.Constraint` to
    represent different permutations of input parameters. These
    constraints are generated by creating an instance of
    :mod:`trappy.plotter.Constraint.ConstraintManager`.

    :param trace: The input data
    :type trace: :mod:`trappy.trace.FTrace` or :mod:`pandas.DataFrame`, list or single

    :param column: specifies the name of the column to
           be plotted.
    :type column: (str, list(str))

    :param templates: TRAPpy events

        .. note::

                This is not required if a :mod:`pandas.DataFrame` is
                used

    :type templates: :mod:`trappy.base.Base`

    :param filters: Filter the column to be plotted as per the
        specified criteria. For Example:
        ::

            filters =
                    {
                        "pid": [ 3338 ],
                        "cpu": [0, 2, 4],
                    }
    :type filters: dict

    :param per_line: Used to control the number of graphs
        in each graph subplot row
    :type per_line: int

    :param concat: Draw all the pivots on a single graph
    :type concat: bool

    :param permute: Draw one plot for each of the traces specified
    :type permute: bool

    :param drawstyle: This argument is forwarded to the matplotlib
        corresponding :func:`matplotlib.pyplot.plot` call

        drawing style.

        .. note::

            step plots are not currently supported for filled
            graphs

    :param xlim: A tuple representing the upper and lower xlimits
    :type xlim: tuple

    :param ylim: A tuple representing the upper and lower ylimits
    :type ylim: tuple

    :param title: A title describing all the generated plots
    :type title: str

    :param style: Created pre-styled graphs loaded from
        :mod:`trappy.plotter.AttrConf.MPL_STYLE`
    :type style: bool

    :param signals: A string of the type event_name:column
        to indicate the value that needs to be plotted

        .. note::

            - Only one of `signals` or both `templates` and
              `columns` should be specified
            - Signals format won't work for :mod:`pandas.DataFrame`
              input

    :type signals: str

    :param legend_ncol: A positive integer that represents the
        number of columns in the legend
    :type legend_ncol: int
    """
    __metaclass__ = ABCMeta

    def __init__(self, traces, templates, **kwargs):
        self._fig = None
        self._layout = None
        super(StaticPlot, self).__init__(traces=traces,
                                         templates=templates)

        self.set_defaults()

        for key in kwargs:
            if key in AttrConf.ARGS_TO_FORWARD:
                self._attr["args_to_forward"][key] = kwargs[key]
            else:
                self._attr[key] = kwargs[key]

        if "signals" in self._attr:
            self._describe_signals()

        self._check_data()

        if "column" not in self._attr:
            raise RuntimeError("Value Column not specified")

        zip_constraints = not self._attr["permute"]
        self.c_mgr = ConstraintManager(traces, self._attr["column"],
                                       self.templates, self._attr["pivot"],
                                       self._attr["filters"], zip_constraints)

    def savefig(self, *args, **kwargs):
        """Save the plot as a PNG fill. This calls into
        :mod:`matplotlib.figure.savefig`
        """

        if self._fig is None:
            self.view()
        self._fig.savefig(*args, **kwargs)

    @abstractmethod
    def set_defaults(self):
        """Sets the default attrs"""
        self._attr["width"] = AttrConf.WIDTH
        self._attr["length"] = AttrConf.LENGTH
        self._attr["per_line"] = AttrConf.PER_LINE
        self._attr["concat"] = AttrConf.CONCAT
        self._attr["filters"] = {}
        self._attr["style"] = True
        self._attr["permute"] = False
        self._attr["pivot"] = AttrConf.PIVOT
        self._attr["xlim"] = AttrConf.XLIM
        self._attr["ylim"] = AttrConf.XLIM
        self._attr["title"] = AttrConf.TITLE
        self._attr["args_to_forward"] = {}
        self._attr["map_label"] = {}
        self._attr["_legend_handles"] = []
        self._attr["_legend_labels"] = []
        self._attr["legend_ncol"] = AttrConf.LEGEND_NCOL

    def view(self, test=False):
        """Displays the graph"""

        if test:
            self._attr["style"] = True
            AttrConf.MPL_STYLE["interactive"] = False

        permute = self._attr["permute"] and not self._attr["concat"]
        if self._attr["style"]:
            with plt.rc_context(AttrConf.MPL_STYLE):
                self._resolve(permute, self._attr["concat"])
        else:
            self._resolve(permute, self._attr["concat"])

    def make_title(self, constraint, pivot, permute, concat):
        """Generates a title string for an axis"""
        if concat:
            return str(constraint)

        if permute:
            return constraint.column
        elif pivot != AttrConf.PIVOT_VAL:
            return "{0}: {1}".format(self._attr["pivot"], self._attr["map_label"].get(pivot, pivot))
        else:
            return ""

    def add_to_legend(self, series_index, handle, constraint, pivot, concat, permute):
        """
        Add series handles and names to the legend
        A handle is returned from a plot on an axis
        e.g. Line2D from axis.plot()
        """
        self._attr["_legend_handles"][series_index] = handle
        legend_labels = self._attr["_legend_labels"]

        if concat and pivot == AttrConf.PIVOT_VAL:
            legend_labels[series_index] = self._attr["column"]
        elif concat:
            legend_labels[series_index] = "{0}: {1}".format(
                self._attr["pivot"],
                self._attr["map_label"].get(pivot, pivot)
            )
        elif permute:
            legend_labels[series_index] = constraint.get_data_name() + ":" + constraint._template.name
        else:
            legend_labels[series_index] = str(constraint)

    def _resolve(self, permute, concat):
        """Determine what data to plot on which axis"""
        pivot_vals, len_pivots = self.c_mgr.generate_pivots(permute)
        pivot_vals = list(pivot_vals)

        num_of_axes = len(self.c_mgr) if concat else len_pivots

        # Create a 2D Layout
        self._layout = PlotLayout(
            self._attr["per_line"],
            num_of_axes,
            width=self._attr["width"],
            length=self._attr["length"],
            title=self._attr['title'])

        self._fig = self._layout.get_fig()

        #Determine what constraint to plot and the corresponding pivot value
        if permute:
            legend_len = self.c_mgr._max_len
            pivots = [y for _, y in pivot_vals]
            c_dict = {c : str(c) for c in self.c_mgr}
            c_list = sorted(c_dict.items(), key=lambda x: (x[1].split(":")[-1], x[1].split(":")[0]))
            constraints = [c[0] for c in c_list]
            cp_pairs = [(c, p) for c in constraints for p in sorted(set(pivots))]
        else:
            legend_len = len_pivots if concat else len(self.c_mgr)
            pivots = pivot_vals
            cp_pairs = [(c, p) for c in self.c_mgr for p in pivots if p in c.result]

        #Initialise legend data and colormap
        self._attr["_legend_handles"] = [None] * legend_len
        self._attr["_legend_labels"] = [None] * legend_len
        self._cmap = ColorMap(legend_len)

        #Group constraints/series with the axis they are to be plotted on
        figure_data = ddict(list)
        for i, (constraint, pivot) in enumerate(cp_pairs):
            axis = self._layout.get_axis(constraint.trace_index if concat else i)
            figure_data[axis].append((constraint, pivot))

        #Plot each axis
        for axis, series_list in figure_data.iteritems():
            self.plot_axis(
                axis,
                series_list,
                permute,
                self._attr["concat"],
                self._attr["args_to_forward"]
            )

        self._fig.legend(self._attr["_legend_handles"],
                         self._attr["_legend_labels"],
                         loc='lower center',
                         ncol=self._attr["legend_ncol"],
                         borderaxespad=0.)

        self._layout.finish(num_of_axes)

    def plot_axis(self, axis, series_list, permute, concat, args_to_forward):
        """Internal Method called to plot data (series_list) on a given axis"""
        raise NotImplementedError("Method Not Implemented")
<|endoftext|>


<commit_before># Copyright (C) 2013  Renato Lima - Akretion
# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html

{
    "name": "Módulo fiscal brasileiro",
    "summary": "Brazilian fiscal core module.",
    "category": "Localisation",
    "license": "AGPL-3",
    "author": "Akretion, Odoo Community Association (OCA)",
    "maintainers": ["renatonlima"],
    "website": "https://github.com/OCA/l10n-brazil",
    "development_status": "Production/Stable",
    "version": "14.0.4.17.1",
    "depends": [
        "uom",
        "product",
        "l10n_br_base",
    ],
    "data": [
        # security
        "security/fiscal_security.xml",
        "security/ir.model.access.csv",
        # Data
        # Some data is being loaded via post_init_hook in hook file
        "data/l10n_br_fiscal_email_template.xml",
        "data/l10n_br_fiscal_data.xml",
        "data/uom_data.xml",
        "data/product_data.xml",
        "data/partner_profile_data.xml",
        "data/res_partner_data.xml",
        "data/l10n_br_fiscal.tax.group.csv",
        "data/l10n_br_fiscal.icms.relief.csv",
        "data/l10n_br_fiscal.document.type.csv",
        "data/l10n_br_fiscal.product.genre.csv",
        "data/l10n_br_fiscal.cst.csv",
        "data/l10n_br_fiscal.tax.csv",
        "data/l10n_br_fiscal.tax.pis.cofins.csv",
        "data/l10n_br_fiscal_server_action.xml",
        "data/ir_cron.xml",
        "data/l10n_br_fiscal_comment_data.xml",
        # Views
        "views/cnae_view.xml",
        "views/cfop_view.xml",
        "views/comment_view.xml",
        "views/cst_view.xml",
        "views/tax_group_view.xml",
        "views/tax_view.xml",
        "views/tax_definition_view.xml",
        "views/icms_regulation_view.xml",
        "views/icms_relief_view.xml",
        "views/tax_pis_cofins_view.xml",
        "views/tax_pis_cofins_base_view.xml",
        "views/tax_pis_cofins_credit_view.xml",
        "views/tax_ipi_control_seal_view.xml",
        "views/tax_ipi_guideline_view.xml",
        "views/tax_ipi_guideline_class_view.xml",
        "views/ncm_view.xml",
        "views/nbm_view.xml",
        "views/nbs_view.xml",
        "views/service_type_view.xml",
        "views/cest_view.xml",
        "views/product_genre_view.xml",
        "views/document_type_view.xml",
        "views/document_serie_view.xml",
        "views/document_email_view.xml",
        "views/certificate_view.xml",
        "views/simplified_tax_view.xml",
        "views/simplified_tax_range_view.xml",
        "views/operation_view.xml",
        "views/operation_line_view.xml",
        "views/product_template_view.xml",
        "views/product_product_view.xml",
        "views/tax_estimate_view.xml",
        "views/partner_profile_view.xml",
        "views/res_partner_view.xml",
        "views/res_company_view.xml",
        "views/document_view.xml",
        "views/document_related_view.xml",
        "views/document_line_view.xml",
        "views/document_fiscal_line_mixin_view.xml",
        "views/res_config_settings_view.xml",
        "views/subsequent_operation_view.xml",
        "views/subsequent_document_view.xml",
        "views/uom_uom.xml",
        "views/closing.xml",
        "views/invalidate_number_view.xml",
        "views/city_taxation_code.xml",
        #        "views/mdfe/mdfe_views.xml",
        #        "views/dfe/dfe_views.xml",
        "views/operation_dashboard_view.xml",
        "views/document_event_view.xml",
        # Wizards
        "wizards/document_cancel_wizard.xml",
        "wizards/document_correction_wizard.xml",
        "wizards/document_status_wizard.xml",
        "wizards/invalidate_number_wizard.xml",
        # Actions
        "views/l10n_br_fiscal_action.xml",
        # Menus
        "views/l10n_br_fiscal_menu.xml",
    ],
    "demo": [
        # Some demo data is being loaded via post_init_hook in hook file
    ],
    "post_init_hook": "post_init_hook",
    "installable": True,
    "application": True,
    "auto_install": False,
    "external_dependencies": {
        "python": [
            "erpbrasil.base",
            "erpbrasil.assinatura-nopyopenssl",
        ]
    },
}
<commit_msg>l10n_br_fiscal 14.0.5.0.0<commit_after># Copyright (C) 2013  Renato Lima - Akretion
# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html

{
    "name": "Módulo fiscal brasileiro",
    "summary": "Brazilian fiscal core module.",
    "category": "Localisation",
    "license": "AGPL-3",
    "author": "Akretion, Odoo Community Association (OCA)",
    "maintainers": ["renatonlima"],
    "website": "https://github.com/OCA/l10n-brazil",
    "development_status": "Production/Stable",
    "version": "14.0.5.0.0",
    "depends": [
        "uom",
        "product",
        "l10n_br_base",
    ],
    "data": [
        # security
        "security/fiscal_security.xml",
        "security/ir.model.access.csv",
        # Data
        # Some data is being loaded via post_init_hook in hook file
        "data/l10n_br_fiscal_email_template.xml",
        "data/l10n_br_fiscal_data.xml",
        "data/uom_data.xml",
        "data/product_data.xml",
        "data/partner_profile_data.xml",
        "data/res_partner_data.xml",
        "data/l10n_br_fiscal.tax.group.csv",
        "data/l10n_br_fiscal.icms.relief.csv",
        "data/l10n_br_fiscal.document.type.csv",
        "data/l10n_br_fiscal.product.genre.csv",
        "data/l10n_br_fiscal.cst.csv",
        "data/l10n_br_fiscal.tax.csv",
        "data/l10n_br_fiscal.tax.pis.cofins.csv",
        "data/l10n_br_fiscal_server_action.xml",
        "data/ir_cron.xml",
        "data/l10n_br_fiscal_comment_data.xml",
        # Views
        "views/cnae_view.xml",
        "views/cfop_view.xml",
        "views/comment_view.xml",
        "views/cst_view.xml",
        "views/tax_group_view.xml",
        "views/tax_view.xml",
        "views/tax_definition_view.xml",
        "views/icms_regulation_view.xml",
        "views/icms_relief_view.xml",
        "views/tax_pis_cofins_view.xml",
        "views/tax_pis_cofins_base_view.xml",
        "views/tax_pis_cofins_credit_view.xml",
        "views/tax_ipi_control_seal_view.xml",
        "views/tax_ipi_guideline_view.xml",
        "views/tax_ipi_guideline_class_view.xml",
        "views/ncm_view.xml",
        "views/nbm_view.xml",
        "views/nbs_view.xml",
        "views/service_type_view.xml",
        "views/cest_view.xml",
        "views/product_genre_view.xml",
        "views/document_type_view.xml",
        "views/document_serie_view.xml",
        "views/document_email_view.xml",
        "views/certificate_view.xml",
        "views/simplified_tax_view.xml",
        "views/simplified_tax_range_view.xml",
        "views/operation_view.xml",
        "views/operation_line_view.xml",
        "views/product_template_view.xml",
        "views/product_product_view.xml",
        "views/tax_estimate_view.xml",
        "views/partner_profile_view.xml",
        "views/res_partner_view.xml",
        "views/res_company_view.xml",
        "views/document_view.xml",
        "views/document_related_view.xml",
        "views/document_line_view.xml",
        "views/document_fiscal_line_mixin_view.xml",
        "views/res_config_settings_view.xml",
        "views/subsequent_operation_view.xml",
        "views/subsequent_document_view.xml",
        "views/uom_uom.xml",
        "views/closing.xml",
        "views/invalidate_number_view.xml",
        "views/city_taxation_code.xml",
        #        "views/mdfe/mdfe_views.xml",
        #        "views/dfe/dfe_views.xml",
        "views/operation_dashboard_view.xml",
        "views/document_event_view.xml",
        # Wizards
        "wizards/document_cancel_wizard.xml",
        "wizards/document_correction_wizard.xml",
        "wizards/document_status_wizard.xml",
        "wizards/invalidate_number_wizard.xml",
        # Actions
        "views/l10n_br_fiscal_action.xml",
        # Menus
        "views/l10n_br_fiscal_menu.xml",
    ],
    "demo": [
        # Some demo data is being loaded via post_init_hook in hook file
    ],
    "post_init_hook": "post_init_hook",
    "installable": True,
    "application": True,
    "auto_install": False,
    "external_dependencies": {
        "python": [
            "erpbrasil.base",
            "erpbrasil.assinatura-nopyopenssl",
        ]
    },
}
<|endoftext|>


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

"""SchedulerServer base."""

from uuid import UUID

import time
import random
import traceback
import logging

from heapq import heappush, heappop
from twisted.internet import reactor, task
from twisted.web import server
from twisted.internet.defer import inlineCallbacks
from txamqp.content import Content
from .base import BaseServer
from .mixins import MySQLMixin, AMQPMixin

logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)

from twisted.web.resource import Resource

class SchedulerServer(BaseServer, AMQPMixin, MySQLMixin):

    heap = []
    # TODO: make this a set()
    unscheduled_items = []
    enqueueCallLater = None
    enqueueloop = None

    def __init__(self, config, port=None):
        super(SchedulerServer, self).__init__(config)
        self.setupAMQP(config)
        self.setupMySQL(config)
        # HTTP interface
        resource = Resource()
        self.function_resource = Resource()
        resource.putChild("function", self.function_resource)
        if port is None:
            port = config["scheduler_server_port"]
        self.site_port = reactor.listenTCP(port, server.Site(resource))
        # Logging, etc
        self.expose(self.remoteRemoveFromHeap)
        self.expose(self.remoteAddToHeap)
        self.expose(self.enqueueUUID)

    def start(self):
        start_deferred = super(SchedulerServer, self).start()
        start_deferred.addCallback(self._schedulerStart)
        return start_deferred

    @inlineCallbacks
    def _schedulerStart(self, started=None):
        yield self.startJobQueue()
        yield self._loadFromMySQL()
        self.enqueueloop = task.LoopingCall(self.enqueue)
        self.enqueueloop.start(1)

    @inlineCallbacks
    def _loadFromMySQL(self):
        data = []
        start = 0
        while len(data) >= 100000 or start == 0:
            sql = """SELECT uuid, type
                     FROM spider_service
                     ORDER BY id LIMIT %s, 100000
                  """ % start
            start += 100000
            data = yield self.mysql.runQuery(sql)
            for row in data:
                self.addToHeap(row["uuid"], row["type"])

    @inlineCallbacks
    def shutdown(self):
        self.enqueueloop.stop()
        try:
            self.enqueueCallLater.cancel()
        except:
            pass
        yield self.stopJobQueue()
        yield super(SchedulerServer, self).shutdown()

    def enqueue(self):
        now = int(time.time())
        # Compare the heap min timestamp with now().
        # If it's time for the item to be queued, pop it, update the
        # timestamp and add it back to the heap for the next go round.
        queued_items = 0
        if self.amqp_queue_size < 100000:
            logger.debug("%s:%s" % (self.heap[0][0], now))
            while self.heap[0][0] < now and queued_items < 1000:
                job = heappop(self.heap)
                uuid = UUID(bytes=job[1][0])
                if not uuid.hex in self.unscheduled_items:
                    queued_items += 1
                    self.chan.basic_publish(
                        exchange=self.amqp_exchange,
                        content=Content(job[1][0]))
                    heappush(self.heap, (now + job[1][1], job[1]))
                else:
                    self.unscheduled_items.remove(uuid.hex)
        else:
            logger.critical('AMQP queue is at or beyond max limit (%d/100000)'
                % self.amqp_queue_size)

    def enqueueUUID(self, uuid):
        logger.debug('enqueueUUID: uuid=%s' % uuid)
        self.chan.basic_publish(
            exchange=self.amqp_exchange,
            content=Content(UUID(uuid).bytes))
        return uuid

    def remoteAddToHeap(self, uuid=None, type=None):
        if uuid and type:
            logger.debug('remoteAddToHeap: uuid=%s, type=%s' % (uuid, type))
            self.addToHeap(uuid, type)
            return {}
        else:
            logger.error('Required parameters are uuid and type')
            return {'error': 'Required parameters are uuid and type'}

    def remoteRemoveFromHeap(self, uuid):
        logger.debug('remoteRemoveFromHeap: uuid=%s' % uuid)
        return self.removeFromHeap(uuid)

    def addToHeap(self, uuid, type):
        # lookup if type is in the service_mapping, if it is
        # then rewrite type to the proper resource
        if not uuid in self.unscheduled_items:
            if self.service_mapping and type in self.service_mapping:
                logger.info('Remapping resource %s to %s'
                    % (type, self.service_mapping[type]))
                type = self.service_mapping[type]
            try:
                # Make sure the uuid is in bytes
                uuid_bytes = UUID(uuid).bytes
            except ValueError:
                logger.error('Cound not turn UUID into bytes using string: "%s" with type of "%s"'
                    % (uuid, type))
                return
            if type in self.functions and 'interval' in self.functions[type]:
                interval = int(self.functions[type]['interval'])
            else:
                logger.error('Could not find interval for type %s' % type)
                return
            # Enqueue randomly over the interval so it doesn't
            # flood the server at the interval time. only if an interval is defined
            if interval:
                enqueue_time = int(time.time() + random.randint(0, interval))
                # Add a UUID to the heap.
                logger.debug('Adding %s to heap with time %s and interval of %s'
                    % (uuid, enqueue_time, interval))
                heappush(self.heap, (enqueue_time, (uuid_bytes, interval)))
        else:
            logger.info('Unscheduling %s' % uuid)
            self.unscheduled_items.remove(uuid)

    def removeFromHeap(self, uuid):
        logger.info('Removing %s from heap' % uuid)
        self.unscheduled_items.append(uuid)

    @inlineCallbacks
    def executeReservation(self, function_name, **kwargs):
        if not isinstance(function_name, str):
            for key in self.functions:
                if self.functions[key]["function"] == function_name:
                    function_name = key
                    break
        if function_name not in self.functions:
            raise Exception("Function %s does not exist." % function_name)
        function = self.functions[function_name]
        logger.error("Calling function %s with kwargs %s" % (function_name, kwargs))
        try:
            data = yield self.executeFunction(function_name, **kwargs)
        except Exception, e:
            tb = traceback.format_exc()
            logger.error("function %s failed with args %s:\n%s" % (
                function_name, kwargs, tb))
        logger.info("function %s returned successfully with %s" % (function_name, data))
        if data is None:
            returnValue({'success':True})
        returnValue(data)

<commit_msg>add missing import (which never raised any visible exception... )<commit_after>#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""SchedulerServer base."""

from uuid import UUID

import time
import random
import traceback
import logging

from heapq import heappush, heappop
from twisted.internet import reactor, task
from twisted.web import server
from twisted.internet.defer import inlineCallbacks, returnValue
from txamqp.content import Content
from .base import BaseServer
from .mixins import MySQLMixin, AMQPMixin

logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)

from twisted.web.resource import Resource

class SchedulerServer(BaseServer, AMQPMixin, MySQLMixin):

    heap = []
    # TODO: make this a set()
    unscheduled_items = []
    enqueueCallLater = None
    enqueueloop = None

    def __init__(self, config, port=None):
        super(SchedulerServer, self).__init__(config)
        self.setupAMQP(config)
        self.setupMySQL(config)
        # HTTP interface
        resource = Resource()
        self.function_resource = Resource()
        resource.putChild("function", self.function_resource)
        if port is None:
            port = config["scheduler_server_port"]
        self.site_port = reactor.listenTCP(port, server.Site(resource))
        # Logging, etc
        self.expose(self.remoteRemoveFromHeap)
        self.expose(self.remoteAddToHeap)
        self.expose(self.enqueueUUID)

    def start(self):
        start_deferred = super(SchedulerServer, self).start()
        start_deferred.addCallback(self._schedulerStart)
        return start_deferred

    @inlineCallbacks
    def _schedulerStart(self, started=None):
        yield self.startJobQueue()
        yield self._loadFromMySQL()
        self.enqueueloop = task.LoopingCall(self.enqueue)
        self.enqueueloop.start(1)

    @inlineCallbacks
    def _loadFromMySQL(self):
        data = []
        start = 0
        while len(data) >= 100000 or start == 0:
            sql = """SELECT uuid, type
                     FROM spider_service
                     ORDER BY id LIMIT %s, 100000
                  """ % start
            start += 100000
            data = yield self.mysql.runQuery(sql)
            for row in data:
                self.addToHeap(row["uuid"], row["type"])

    @inlineCallbacks
    def shutdown(self):
        self.enqueueloop.stop()
        try:
            self.enqueueCallLater.cancel()
        except:
            pass
        yield self.stopJobQueue()
        yield super(SchedulerServer, self).shutdown()

    def enqueue(self):
        now = int(time.time())
        # Compare the heap min timestamp with now().
        # If it's time for the item to be queued, pop it, update the
        # timestamp and add it back to the heap for the next go round.
        queued_items = 0
        if self.amqp_queue_size < 100000:
            logger.debug("%s:%s" % (self.heap[0][0], now))
            while self.heap[0][0] < now and queued_items < 1000:
                job = heappop(self.heap)
                uuid = UUID(bytes=job[1][0])
                if not uuid.hex in self.unscheduled_items:
                    queued_items += 1
                    self.chan.basic_publish(
                        exchange=self.amqp_exchange,
                        content=Content(job[1][0]))
                    heappush(self.heap, (now + job[1][1], job[1]))
                else:
                    self.unscheduled_items.remove(uuid.hex)
        else:
            logger.critical('AMQP queue is at or beyond max limit (%d/100000)'
                % self.amqp_queue_size)

    def enqueueUUID(self, uuid):
        logger.debug('enqueueUUID: uuid=%s' % uuid)
        self.chan.basic_publish(
            exchange=self.amqp_exchange,
            content=Content(UUID(uuid).bytes))
        return uuid

    def remoteAddToHeap(self, uuid=None, type=None):
        if uuid and type:
            logger.debug('remoteAddToHeap: uuid=%s, type=%s' % (uuid, type))
            self.addToHeap(uuid, type)
            return {}
        else:
            logger.error('Required parameters are uuid and type')
            return {'error': 'Required parameters are uuid and type'}

    def remoteRemoveFromHeap(self, uuid):
        logger.debug('remoteRemoveFromHeap: uuid=%s' % uuid)
        return self.removeFromHeap(uuid)

    def addToHeap(self, uuid, type):
        # lookup if type is in the service_mapping, if it is
        # then rewrite type to the proper resource
        if not uuid in self.unscheduled_items:
            if self.service_mapping and type in self.service_mapping:
                logger.info('Remapping resource %s to %s'
                    % (type, self.service_mapping[type]))
                type = self.service_mapping[type]
            try:
                # Make sure the uuid is in bytes
                uuid_bytes = UUID(uuid).bytes
            except ValueError:
                logger.error('Cound not turn UUID into bytes using string: "%s" with type of "%s"'
                    % (uuid, type))
                return
            if type in self.functions and 'interval' in self.functions[type]:
                interval = int(self.functions[type]['interval'])
            else:
                logger.error('Could not find interval for type %s' % type)
                return
            # Enqueue randomly over the interval so it doesn't
            # flood the server at the interval time. only if an interval is defined
            if interval:
                enqueue_time = int(time.time() + random.randint(0, interval))
                # Add a UUID to the heap.
                logger.debug('Adding %s to heap with time %s and interval of %s'
                    % (uuid, enqueue_time, interval))
                heappush(self.heap, (enqueue_time, (uuid_bytes, interval)))
        else:
            logger.info('Unscheduling %s' % uuid)
            self.unscheduled_items.remove(uuid)

    def removeFromHeap(self, uuid):
        logger.info('Removing %s from heap' % uuid)
        self.unscheduled_items.append(uuid)

    @inlineCallbacks
    def executeReservation(self, function_name, **kwargs):
        if not isinstance(function_name, str):
            for key in self.functions:
                if self.functions[key]["function"] == function_name:
                    function_name = key
                    break
        if function_name not in self.functions:
            raise Exception("Function %s does not exist." % function_name)
        function = self.functions[function_name]
        logger.debug("Calling function %s with kwargs %s" % (function_name, kwargs))
        try:
            data = yield self.executeFunction(function_name, **kwargs)
        except Exception, e:
            tb = traceback.format_exc()
            logger.error("function %s failed with args %s:\n%s" % (
                function_name, kwargs, tb))
        if data is None:
            returnValue({'success':True})
        returnValue(data)

<|endoftext|>


<commit_before>#!/usr/bin/env python
# -*- encoding: utf-8 -*-
# CREATED:2015-03-06 14:24:58 by Brian McFee <brian.mcfee@nyu.edu>
'''Unit tests for JAMS core objects'''

import os
import tempfile
import json
import jsonschema
import six
import warnings
import numpy as np
import pandas as pd

from nose.tools import raises, eq_

import jams

# JObject

def test_jobject_dict():

    data = dict(key1='value 1', key2='value 2')

    J = jams.JObject(**data)

    jdict = J.__dict__

    eq_(data, jdict)

def test_jobject_serialize():

    data = dict(key1='value 1', key2='value 2')

    json_data = json.dumps(data, indent=2)

    J = jams.JObject(**data)

    json_jobject = J.dumps(indent=2)

    eq_(json_data, json_jobject)

def test_jobject_deserialize():

    data = dict(key1='value 1', key2='value 2')

    json_data = json.dumps(data, indent=2)

    J = jams.JObject.loads(json_data)

    json_jobject = J.dumps(indent=2)

    eq_(json_data, json_jobject)

def test_jobject_eq():

    def __test(d1, d2, match):

        J1 = jams.JObject(**d1)
        J2 = jams.JObject(**d2)

        # Test self-equivalence
        assert J1 == J1
        assert J2 == J2

        # Test equivalence in both directions
        assert (J1 == J2) == match
        assert (J2 == J1) == match

    data_1 = dict(key1='value 1', key2='value 2')
    data_2 = dict(key1='value 1', key2='value 2')
    data_3 = dict(key1='value 1', key2='value 3')

    yield __test, data_1, data_1, True
    yield __test, data_1, data_2, True
    yield __test, data_1, data_3, False

def test_jobject_nonzero():

    def __test(d, value):
        J = jams.JObject(**d)

        eq_(J.__nonzero__(), value)

    yield __test, {'key': True}, True
    yield __test, {'key': False}, False
    yield __test, {}, False

# Sandbox

def test_sandbox():

    data = dict(key1='value 1', key2='value 2')

    J = jams.Sandbox(**data)

    for key, value in six.iteritems(data):
        eq_(value, J[key])

# JamsFrame

def test_jamsframe_fields():

    eq_(jams.JamsFrame.fields(), ['time', 'duration', 'value', 'confidence'])

def test_jamsframe_from_df():

    df = pd.DataFrame(data=[[0.0, 1.0, 'a', 0.0],
                            [1.0, 2.0, 'b', 0.0]],
                      columns=['time', 'duration', 'value', 'confidence'])

    jf = jams.JamsFrame.from_dataframe(df)

    # 1. type check
    assert isinstance(jf, jams.JamsFrame)

    # 2. check field order
    eq_(list(jf.keys().values),
        jams.JamsFrame.fields())

    # 3. check field types
    assert jf['time'].dtype == np.dtype('<m8[ns]')
    assert jf['duration'].dtype == np.dtype('<m8[ns]')

    # 4. Check the values
    eq_(list(jf['time']),
        list(pd.to_timedelta([0.0, 1.0], unit='s')))
    eq_(list(jf['duration']),
        list(pd.to_timedelta([1.0, 2.0], unit='s')))
    eq_(list(jf['value']), ['a', 'b'])
    eq_(list(jf['confidence']), [0.0, 0.0])

def test_jamsframe_add_observation():
    df = pd.DataFrame(data=[[0.0, 1.0, 'a', 0.0],
                            [1.0, 2.0, 'b', 0.0]],
                      columns=['time', 'duration', 'value', 'confidence'])

    jf = jams.JamsFrame.from_dataframe(df)

    jf.add_observation(time=3.0, duration=1.0, value='c', confidence=0.0)

    eq_(list(jf['time']),
        list(pd.to_timedelta([0.0, 1.0, 3.0], unit='s')))
    eq_(list(jf['duration']),
        list(pd.to_timedelta([1.0, 2.0, 1.0], unit='s')))
    eq_(list(jf['value']), ['a', 'b', 'c'])
    eq_(list(jf['confidence']), [0.0, 0.0, 0.0])

def test_jamsframe_interval_values():

    df = pd.DataFrame(data=[[0.0, 1.0, 'a', 0.0],
                            [1.0, 2.0, 'b', 0.0]],
                      columns=['time', 'duration', 'value', 'confidence'])

    jf = jams.JamsFrame.from_dataframe(df)

    intervals, values = jf.to_interval_values()

    assert np.allclose(intervals, np.array([[0.0, 1.0], [1.0, 3.0]]))
    eq_(values, ['a', 'b'])

def test_jamsframe_serialize():

    def __test(dense):
        df = pd.DataFrame(data=[[0.0, 1.0, 'a', 0.0],
                                [1.0, 2.0, 'b', 0.0]],
                          columns=['time', 'duration', 'value', 'confidence'])

        jf = jams.JamsFrame.from_dataframe(df)
        jf.dense = dense

        jf_s = jf.__json__

        jf2 = jams.JamsFrame.from_dict(jf_s)

        for key in jams.JamsFrame.fields():
            eq_(list(jf[key]), list(jf2[key]))

    for dense in [False, True]:
        yield __test, dense

# Curator
def test_curator():

    c = jams.Curator(name='myself', email='you@me.com')

    eq_(c.name, 'myself')
    eq_(c.email, 'you@me.com')

# AnnotationMetadata

def test_annotation_metadata():

    def __test(data, curator, annotator):

        md = jams.AnnotationMetadata(curator=curator, annotator=annotator,
                                     **data)

        if curator is not None:
            eq_(dict(md.curator), dict(curator))

        if annotator is not None:
            eq_(dict(md.annotator), dict(annotator))

        real_data = dict(md)
        real_data.pop('curator')
        real_data.pop('annotator')
        eq_(real_data, data)

    dummies = dict(version='0',
                   corpus='test',
                   annotation_tools='nose',
                   annotation_rules='brains',
                   validation='unnecessary',
                   data_source='null')

    real_curator = jams.Curator(name='nobody', email='none@none.com')

    real_annotator = jams.Sandbox(description='none')

    for curator in [None, real_curator]:
        for annotator in [None, real_annotator]:
            yield __test, dummies, curator, annotator

# Annotation
def test_annotation():

    def __test(namespace, data, amd, sandbox):
        ann = jams.Annotation(namespace,
                              data=data,
                              annotation_metadata=amd,
                              sandbox=sandbox)

        eq_(namespace, ann.namespace)

        if amd is not None:
            eq_(dict(amd), dict(ann.annotation_metadata))

        if sandbox is not None:
            eq_(dict(sandbox), dict(ann.sandbox))

        if data is not None:
            assert ann.data.equals(jams.JamsFrame.from_dict(data))

    real_sandbox = jams.Sandbox(description='none')
    real_amd = jams.AnnotationMetadata(corpus='test collection')
    real_data = dict(time=[0.0, 1.0],
                     duration=[0.5, 0.5],
                     value=['one', 'two'],
                     confidence=[0.9, 0.9])

    namespace = 'tag_open'

    for data in [None, real_data]:
        for amd in [None, real_amd]:
            for sandbox in [None, real_sandbox]:
                yield __test, namespace, data, amd, sandbox

def test_annotation_append():

    data = dict(time=[0.0, 1.0],
                duration=[0.5, 0.5],
                value=['one', 'two'],
                confidence=[0.9, 0.9])

    namespace = 'tag_open'

    ann = jams.Annotation(namespace, data=data)

    update = dict(time=2.0, duration=1.0, value='three', confidence=0.8)

    ann.append(**update)

    jf = jams.JamsFrame.from_dict(data)
    jf.add_observation(**update)

    assert ann.data.equals(jf)

# FileMetadata

def test_filemetadata():

    meta = dict(title='Test track',
                artist='Test artist',
                release='Test release',
                duration=31.3)

    fm = jams.FileMetadata(**meta)
    dict_fm = dict(fm)

    for k in meta:
        eq_(meta[k], dict_fm[k])

# AnnotationArray

def test_annotation_array():

    arr = jams.AnnotationArray()

    eq_(len(arr), 0)

def test_annotation_array_data():

    data = dict(time=[0.0, 1.0],
                duration=[0.5, 0.5],
                value=['one', 'two'],
                confidence=[0.9, 0.9])

    namespace = 'tag_open'
    ann = jams.Annotation(namespace, data=data)

    arr = jams.AnnotationArray(annotations=[ann, ann])

    eq_(len(arr), 2)
    arr.append(ann)

    eq_(len(arr), 3)

    for t_ann in arr:
        assert ann.data.equals(t_ann.data)

def test_annotation_array_serialize():

    data = dict(time=[0.0, 1.0],
                duration=[0.5, 0.5],
                value=['one', 'two'],
                confidence=[0.9, 0.9])

    namespace = 'tag_open'
    ann = jams.Annotation(namespace, data=data)

    arr = jams.AnnotationArray(annotations=[ann, ann])

    arr_js = arr.__json__

    arr2 = jams.AnnotationArray(annotations=arr_js)

    eq_(arr, arr2)

# JAMS

def test_load_fail():
    # 1. test bad file path
    # 2. test non-json file

    def __test(filename):
        jams.load(filename)

    # Make a non-existent file
    tdir = tempfile.mkdtemp()
    yield raises(IOError)(__test), os.path.join(tdir, 'nonexistent.jams')
    os.rmdir(tdir)

    # Make a non-json file
    tdir = tempfile.mkdtemp()
    badfile = os.path.join(tdir, 'nonexistent.jams')
    with open(badfile, mode='w') as fp:
        fp.write('some garbage')
    yield raises(ValueError)(__test), os.path.join(tdir, 'nonexistent.jams')
    os.unlink(badfile)
    os.rmdir(tdir)

def test_load_valid():

    # 3. test good jams file with strict validation
    # 4. test good jams file without strict validation

    def __test(filename, valid, strict):
        jams.load(filename, validate=valid, strict=strict)

    fn = 'fixtures/valid.jams'

    for validate in [False, True]:
        for strict in [False, True]:
            yield __test, fn, validate, strict

def test_load_invalid():

    def __test(filename, valid, strict):
        jams.load(filename, validate=valid, strict=strict)

    def __test_warn(filename, valid, strict):
        warnings.resetwarnings()
        with warnings.catch_warnings(record=True) as out:
            jams.load(filename, validate=valid, strict=strict)

        assert len(out) > 0
        assert out[0].category is UserWarning
        assert 'failed validating' in str(out[0].message).lower()

    # 5. test bad jams file with strict validation
    # 6. test bad jams file without strict validation
    fn = 'fixtures/invalid.jams'

    # Test once with no validation
    yield __test, fn, False, False

    # With validation, failure can either be a warning or an exception
    yield raises(jsonschema.ValidationError)(__test), fn, True, True

    yield __test_warn, fn, True, False

<commit_msg>added dict-serialize test in jamsframe<commit_after>#!/usr/bin/env python
# -*- encoding: utf-8 -*-
# CREATED:2015-03-06 14:24:58 by Brian McFee <brian.mcfee@nyu.edu>
'''Unit tests for JAMS core objects'''

import os
import tempfile
import json
import jsonschema
import six
import warnings
import numpy as np
import pandas as pd

from nose.tools import raises, eq_

import jams

# JObject

def test_jobject_dict():

    data = dict(key1='value 1', key2='value 2')

    J = jams.JObject(**data)

    jdict = J.__dict__

    eq_(data, jdict)

def test_jobject_serialize():

    data = dict(key1='value 1', key2='value 2')

    json_data = json.dumps(data, indent=2)

    J = jams.JObject(**data)

    json_jobject = J.dumps(indent=2)

    eq_(json_data, json_jobject)

def test_jobject_deserialize():

    data = dict(key1='value 1', key2='value 2')

    json_data = json.dumps(data, indent=2)

    J = jams.JObject.loads(json_data)

    json_jobject = J.dumps(indent=2)

    eq_(json_data, json_jobject)

def test_jobject_eq():

    def __test(d1, d2, match):

        J1 = jams.JObject(**d1)
        J2 = jams.JObject(**d2)

        # Test self-equivalence
        assert J1 == J1
        assert J2 == J2

        # Test equivalence in both directions
        assert (J1 == J2) == match
        assert (J2 == J1) == match

    data_1 = dict(key1='value 1', key2='value 2')
    data_2 = dict(key1='value 1', key2='value 2')
    data_3 = dict(key1='value 1', key2='value 3')

    yield __test, data_1, data_1, True
    yield __test, data_1, data_2, True
    yield __test, data_1, data_3, False

def test_jobject_nonzero():

    def __test(d, value):
        J = jams.JObject(**d)

        eq_(J.__nonzero__(), value)

    yield __test, {'key': True}, True
    yield __test, {'key': False}, False
    yield __test, {}, False

# Sandbox

def test_sandbox():

    data = dict(key1='value 1', key2='value 2')

    J = jams.Sandbox(**data)

    for key, value in six.iteritems(data):
        eq_(value, J[key])

# JamsFrame

def test_jamsframe_fields():

    eq_(jams.JamsFrame.fields(), ['time', 'duration', 'value', 'confidence'])

def test_jamsframe_from_df():

    df = pd.DataFrame(data=[[0.0, 1.0, 'a', 0.0],
                            [1.0, 2.0, 'b', 0.0]],
                      columns=['time', 'duration', 'value', 'confidence'])

    jf = jams.JamsFrame.from_dataframe(df)

    # 1. type check
    assert isinstance(jf, jams.JamsFrame)

    # 2. check field order
    eq_(list(jf.keys().values),
        jams.JamsFrame.fields())

    # 3. check field types
    assert jf['time'].dtype == np.dtype('<m8[ns]')
    assert jf['duration'].dtype == np.dtype('<m8[ns]')

    # 4. Check the values
    eq_(list(jf['time']),
        list(pd.to_timedelta([0.0, 1.0], unit='s')))
    eq_(list(jf['duration']),
        list(pd.to_timedelta([1.0, 2.0], unit='s')))
    eq_(list(jf['value']), ['a', 'b'])
    eq_(list(jf['confidence']), [0.0, 0.0])

def test_jamsframe_add_observation():
    df = pd.DataFrame(data=[[0.0, 1.0, 'a', 0.0],
                            [1.0, 2.0, 'b', 0.0]],
                      columns=['time', 'duration', 'value', 'confidence'])

    jf = jams.JamsFrame.from_dataframe(df)

    jf.add_observation(time=3.0, duration=1.0, value='c', confidence=0.0)

    eq_(list(jf['time']),
        list(pd.to_timedelta([0.0, 1.0, 3.0], unit='s')))
    eq_(list(jf['duration']),
        list(pd.to_timedelta([1.0, 2.0, 1.0], unit='s')))
    eq_(list(jf['value']), ['a', 'b', 'c'])
    eq_(list(jf['confidence']), [0.0, 0.0, 0.0])

def test_jamsframe_interval_values():

    df = pd.DataFrame(data=[[0.0, 1.0, 'a', 0.0],
                            [1.0, 2.0, 'b', 0.0]],
                      columns=['time', 'duration', 'value', 'confidence'])

    jf = jams.JamsFrame.from_dataframe(df)

    intervals, values = jf.to_interval_values()

    assert np.allclose(intervals, np.array([[0.0, 1.0], [1.0, 3.0]]))
    eq_(values, ['a', 'b'])

def test_jamsframe_serialize():

    def __test(dense, data):
        df = pd.DataFrame(data=data,
                          columns=['time', 'duration', 'value', 'confidence'])

        jf = jams.JamsFrame.from_dataframe(df)
        jf.dense = dense

        jf_s = jf.__json__

        jf2 = jams.JamsFrame.from_dict(jf_s)

        for key in jams.JamsFrame.fields():
            eq_(list(jf[key]), list(jf2[key]))

    values = [['a', 'b'], [dict(a=1), dict(b=2)]]

    for value in values:
        data = [[0.0, 1.0, value[0], 0.0],
                [1.0, 2.0, value[1], 0.0]]
        for dense in [False, True]:
            yield __test, dense, data

# Curator
def test_curator():

    c = jams.Curator(name='myself', email='you@me.com')

    eq_(c.name, 'myself')
    eq_(c.email, 'you@me.com')

# AnnotationMetadata

def test_annotation_metadata():

    def __test(data, curator, annotator):

        md = jams.AnnotationMetadata(curator=curator, annotator=annotator,
                                     **data)

        if curator is not None:
            eq_(dict(md.curator), dict(curator))

        if annotator is not None:
            eq_(dict(md.annotator), dict(annotator))

        real_data = dict(md)
        real_data.pop('curator')
        real_data.pop('annotator')
        eq_(real_data, data)

    dummies = dict(version='0',
                   corpus='test',
                   annotation_tools='nose',
                   annotation_rules='brains',
                   validation='unnecessary',
                   data_source='null')

    real_curator = jams.Curator(name='nobody', email='none@none.com')

    real_annotator = jams.Sandbox(description='none')

    for curator in [None, real_curator]:
        for annotator in [None, real_annotator]:
            yield __test, dummies, curator, annotator

# Annotation
def test_annotation():

    def __test(namespace, data, amd, sandbox):
        ann = jams.Annotation(namespace,
                              data=data,
                              annotation_metadata=amd,
                              sandbox=sandbox)

        eq_(namespace, ann.namespace)

        if amd is not None:
            eq_(dict(amd), dict(ann.annotation_metadata))

        if sandbox is not None:
            eq_(dict(sandbox), dict(ann.sandbox))

        if data is not None:
            assert ann.data.equals(jams.JamsFrame.from_dict(data))

    real_sandbox = jams.Sandbox(description='none')
    real_amd = jams.AnnotationMetadata(corpus='test collection')
    real_data = dict(time=[0.0, 1.0],
                     duration=[0.5, 0.5],
                     value=['one', 'two'],
                     confidence=[0.9, 0.9])

    namespace = 'tag_open'

    for data in [None, real_data]:
        for amd in [None, real_amd]:
            for sandbox in [None, real_sandbox]:
                yield __test, namespace, data, amd, sandbox

def test_annotation_append():

    data = dict(time=[0.0, 1.0],
                duration=[0.5, 0.5],
                value=['one', 'two'],
                confidence=[0.9, 0.9])

    namespace = 'tag_open'

    ann = jams.Annotation(namespace, data=data)

    update = dict(time=2.0, duration=1.0, value='three', confidence=0.8)

    ann.append(**update)

    jf = jams.JamsFrame.from_dict(data)
    jf.add_observation(**update)

    assert ann.data.equals(jf)

# FileMetadata

def test_filemetadata():

    meta = dict(title='Test track',
                artist='Test artist',
                release='Test release',
                duration=31.3)

    fm = jams.FileMetadata(**meta)
    dict_fm = dict(fm)

    for k in meta:
        eq_(meta[k], dict_fm[k])

# AnnotationArray

def test_annotation_array():

    arr = jams.AnnotationArray()

    eq_(len(arr), 0)

def test_annotation_array_data():

    data = dict(time=[0.0, 1.0],
                duration=[0.5, 0.5],
                value=['one', 'two'],
                confidence=[0.9, 0.9])

    namespace = 'tag_open'
    ann = jams.Annotation(namespace, data=data)

    arr = jams.AnnotationArray(annotations=[ann, ann])

    eq_(len(arr), 2)
    arr.append(ann)

    eq_(len(arr), 3)

    for t_ann in arr:
        assert ann.data.equals(t_ann.data)

def test_annotation_array_serialize():

    data = dict(time=[0.0, 1.0],
                duration=[0.5, 0.5],
                value=['one', 'two'],
                confidence=[0.9, 0.9])

    namespace = 'tag_open'
    ann = jams.Annotation(namespace, data=data)

    arr = jams.AnnotationArray(annotations=[ann, ann])

    arr_js = arr.__json__

    arr2 = jams.AnnotationArray(annotations=arr_js)

    eq_(arr, arr2)

# JAMS

def test_load_fail():
    # 1. test bad file path
    # 2. test non-json file

    def __test(filename):
        jams.load(filename)

    # Make a non-existent file
    tdir = tempfile.mkdtemp()
    yield raises(IOError)(__test), os.path.join(tdir, 'nonexistent.jams')
    os.rmdir(tdir)

    # Make a non-json file
    tdir = tempfile.mkdtemp()
    badfile = os.path.join(tdir, 'nonexistent.jams')
    with open(badfile, mode='w') as fp:
        fp.write('some garbage')
    yield raises(ValueError)(__test), os.path.join(tdir, 'nonexistent.jams')
    os.unlink(badfile)
    os.rmdir(tdir)

def test_load_valid():

    # 3. test good jams file with strict validation
    # 4. test good jams file without strict validation

    def __test(filename, valid, strict):
        jams.load(filename, validate=valid, strict=strict)

    fn = 'fixtures/valid.jams'

    for validate in [False, True]:
        for strict in [False, True]:
            yield __test, fn, validate, strict

def test_load_invalid():

    def __test(filename, valid, strict):
        jams.load(filename, validate=valid, strict=strict)

    def __test_warn(filename, valid, strict):
        warnings.resetwarnings()
        with warnings.catch_warnings(record=True) as out:
            jams.load(filename, validate=valid, strict=strict)

        assert len(out) > 0
        assert out[0].category is UserWarning
        assert 'failed validating' in str(out[0].message).lower()

    # 5. test bad jams file with strict validation
    # 6. test bad jams file without strict validation
    fn = 'fixtures/invalid.jams'

    # Test once with no validation
    yield __test, fn, False, False

    # With validation, failure can either be a warning or an exception
    yield raises(jsonschema.ValidationError)(__test), fn, True, True

    yield __test_warn, fn, True, False

<|endoftext|>


<commit_before>import datetime

own_bids = []
own_asks = []
bids = []
asks = []
message_id = 0

def create_ask(id, price, quantity, timeout):
    return create_msg(id, type='ask', price=price, quantity=quantity, timeout=timeout)

def create_bid(id, price, quantity, timeout):
    return create_msg(id, type='bid', price=price, quantity=quantity, timeout=timeout)

def create_trade(id, quantity, trade_id):
    return create_msg(id, type='trade', quantity=quantity, trade_id=trade_id)

def create_greeting(id):
    return create_msg(id, type='greeting')

def create_msg(id, type=None, price=None, quantity=None, timeout=None, trade_id=None):
    '''
    Standard for message passing.

    Message can have 5 types: ask, bid, trade, cancel, greeting.
    Depending on the type of message, an argument might be mandatory.
    '''
    global message_id

    message = {
        "id": id,
        "message-id": message_id,
        "timestamp": datetime.datetime.now().isoformat(),
        "type": type,
    }

    message_id = message_id + 1

    if type in ["ask", "bid"]:
        message.update({
            "price": price,
            "quantity": quantity,
            "timeout": timeout
        })
        if type == "ask":
            own_asks.append(message)
        else:
            own_bids.append(message)
    elif type == "trade":
        message.update({
            "quantity": quantity,
            "trade-id": trade_id,
        })
    elif type == "cancel":
        message.update({
            "trade-id": trade_id,
        })

    return message

def trade_offer(their_offer, own_offer):
    return create_trade(
        id = own_offer['id'],
        quantity = own_offer['quantity'],
        trade_id = "{};{}".format(their_offer['id'], their_offer['message-id'])
    )

def match_bid(bid, asks=asks):
    '''Match a bid of your own with the lowest ask from the other party.'''
    matching_asks = filter(lambda ask: ask['price'] <= bid['price'], asks)
    return lowest_offer(matching_asks)

def match_incoming_bid(bid):
    '''Match a bid from the other party with your own asks.'''
    matching_asks = filter(lambda ask: ask['price'] >= bid['price'], asks)
    return highest_offer(matching_asks)

def match_ask(ask, bids=bids):
    '''Match an ask of your own with the highest bid from the other party.'''
    matching_bids = filter(lambda bid: bid['price'] >= ask['price'], bids)
    return highest_offer(matching_bids)

def match_incoming_ask(ask):
    '''Match an ask from the other party with your own bids'''
    matching_bids = filter(lambda bid: bid['price'] <= ask['price'], own_bids)
    return lowest_offer(matching_bids)

def lowest_offer(offers):
    return min(offers, key=lambda x: x['price']) if offers else None

def highest_offer(offers):
    return max(offers, key=lambda x: x['price']) if offers else None

def remove_offer(id, message_id, offers=[]):
    for offer in offers:
        if offers['id'] == id and offers['message-id'] == message_id:
            offers.remove(offer)
<commit_msg>Add confirm message creation to orderbook.<commit_after>import datetime

own_bids = []
own_asks = []
trades = []
bids = []
asks = []
message_id = 0

def create_ask(id, price, quantity, timeout):
    return create_msg(id, type='ask', price=price, quantity=quantity, timeout=timeout)

def create_bid(id, price, quantity, timeout):
    return create_msg(id, type='bid', price=price, quantity=quantity, timeout=timeout)

def create_trade(id, quantity, trade_id):
    return create_msg(id, type='trade', quantity=quantity, trade_id=trade_id)

def create_confirm(id, trade_id):
    return create_msg(id, type='confirm', trade_id=trade_id)

def create_greeting(id):
    return create_msg(id, type='greeting')

def create_msg(id, type=None, price=None, quantity=None, timeout=None, trade_id=None):
    '''
    Standard for message passing.

    Message can have 5 types: ask, bid, trade, cancel, greeting.
    Depending on the type of message, an argument might be mandatory.
    '''
    global message_id

    message = {
        "id": id,
        "message-id": message_id,
        "timestamp": datetime.datetime.now().isoformat(),
        "type": type,
    }

    message_id = message_id + 1

    if type in ["ask", "bid"]:
        message.update({
            "price": price,
            "quantity": quantity,
            "timeout": timeout
        })
        if type == "ask":
            own_asks.append(message)
        else:
            own_bids.append(message)
    elif type == "trade":
        message.update({
            "quantity": quantity,
            "trade-id": trade_id,
        })
    elif type == 'confirm':
        message.update({
            "trade-id": trade_id,
        })
    elif type == "cancel":
        message.update({
            "trade-id": trade_id,
        })

    return message

def trade_offer(their_offer, own_offer):
    if their_offer['type'] == 'bid':
        own_asks.remove(own_offer)
        print own_asks
    else:
        own_bids.remove(own_offer)
        print own_bids
    trades.append(own_offer)
    print trades
    return create_trade(
        id = own_offer['id'],
        quantity = own_offer['quantity'],
        trade_id = "{};{}".format(their_offer['id'], their_offer['message-id'])
    )

def match_bid(bid, asks=asks):
    '''Match a bid of your own with the lowest ask from the other party.'''
    matching_asks = filter(lambda ask: ask['price'] <= bid['price'], asks)
    return lowest_offer(matching_asks)

def match_incoming_bid(bid):
    '''Match a bid from the other party with your own asks.'''
    matching_asks = filter(lambda ask: ask['price'] >= bid['price'], asks)
    return highest_offer(matching_asks)

def match_ask(ask, bids=bids):
    '''Match an ask of your own with the highest bid from the other party.'''
    matching_bids = filter(lambda bid: bid['price'] >= ask['price'], bids)
    return highest_offer(matching_bids)

def match_incoming_ask(ask):
    '''Match an ask from the other party with your own bids'''
    matching_bids = filter(lambda bid: bid['price'] <= ask['price'], own_bids)
    return lowest_offer(matching_bids)

def lowest_offer(offers):
    return min(offers, key=lambda x: x['price']) if offers else None

def highest_offer(offers):
    return max(offers, key=lambda x: x['price']) if offers else None

def remove_offer(id, message_id, offers=[]):
    for offer in offers:
        if offers['id'] == id and offers['message-id'] == message_id:
            offers.remove(offer)
<|endoftext|>


<commit_before>from ConfigParser import SafeConfigParser, NoOptionError
import re
import os

__all__ = ['FormatError', 'LibraryInfo', 'VariablesSet', 'get_info']

_VAR = re.compile('\$\{([a-zA-Z0-9_-]+)\}')

class FormatError(IOError):
    def __init__(self, msg):
        self.msg = msg

    def __str__(self):
        return self.msg

class LibraryInfo(object):
    def __init__(self, name, description, version, sections, vars, requires=None):
        self.name = name
        self.description = description
        if requires:
            self.requires = requires
        else:
            self.requires = []
        self.version = version
        self._sections = sections
        self.vars = vars

    def sections(self):
        return self._sections.keys()

    def cflags(self, section="default"):
        return self.vars.interpolate(self._sections[section]['cflags'])

    def libs(self, section="default"):
        return self.vars.interpolate(self._sections[section]['libs'])

    def __str__(self):
        m = ['Name: %s' % self.name]
        m.append('Description: %s' % self.description)
        if self.requires:
            m.append('Requires:')
        else:
            m.append('Requires: %s' % ",".join(self.requires))
        m.append('Version: %s' % self.version)

        return "\n".join(m)

class VariableSet(object):
    def __init__(self, d):
        self._raw_data = dict([(k, v) for k, v in d.items()])

        self._re = {}
        self._re_sub = {}

        self._init_parse()

    def _init_parse(self):
        for k, v in self._raw_data.items():
            self._init_parse_var(k, v)

    def _init_parse_var(self, name, value):
        self._re[name] = re.compile(r'\$\{%s\}' % name)
        self._re_sub[name] = value

    def interpolate(self, value):
        # Brute force: we keep interpolating until there is no '${var}' anymore
        # or until interpolated string is equal to input string
        def _interpolate(value):
            for k in self._re.keys():
                value = self._re[k].sub(self._re_sub[k], value)
            return value
        while _VAR.search(value):
            nvalue = _interpolate(value)
            if nvalue == value:
                break
            value = nvalue

        return value

    def variables(self):
        return self._raw_data.keys()

    # Emulate a dict to set/get variables values
    def __getitem__(self, name):
        return self._raw_data[name]

    def __setitem__(self, name, value):
        self._raw_data[name] = value
        self._init_parse_var(name, value)

def parse_meta(config):
    if not config.has_section('meta'):
        raise FormatError("No meta section found !")

    d = {}
    for name, value in config.items('meta'):
        d[name] = value

    for k in ['name', 'description', 'version']:
        if not d.has_key(k):
            raise FormatError("Option %s (section [meta]) is mandatory, "
                "but not found" % k)

    if not d.has_key('requires'):
        d['requires'] = []

    return d

def parse_variables(config):
    if not config.has_section('variables'):
        raise FormatError("No variables section found !")

    d = {}

    for name, value in config.items("variables"):
        d[name] = value

    return VariableSet(d)

def parse_sections(config):
    return meta_d, r

def pkg_to_filename(pkg_name):
    return "%s.ini" % pkg_name

def parse_config(filename, dirs=None):
    if dirs:
        filenames = [os.path.join(d, filename) for d in dirs]
    else:
        filenames = [filename]

    config = SafeConfigParser()
    n = config.read(filenames)
    if not len(n) >= 1:
        raise IOError("Could not find file(s) %s" % str(filenames))

    # Parse meta and variables sections
    meta = parse_meta(config)

    vars = {}
    if config.has_section('variables'):
        for name, value in config.items("variables"):
            vars[name] = value

    # Parse "normal" sections
    secs = [s for s in config.sections() if not s in ['meta', 'variables']]
    sections = {}

    requires = {}
    for s in secs:
        d = {}
        if config.has_option(s, "requires"):
            requires[s] = config.get(s, 'requires')

        for name, value in config.items(s):
            d[name] = value
        sections[s] = d

    return meta, vars, sections, requires

def read_config(filenames, dirs=None):
    def _read_config(f):
        meta, vars, sections, reqs = parse_config(f, dirs)
        # recursively add sections and variables of required libraries
        for rname, rvalue in reqs.items():
            nmeta, nvars, nsections, nreqs = _read_config(pkg_to_filename(rvalue))

            # Update var dict for variables not in 'top' config file
            for k, v in nvars.items():
                if not vars.has_key(k):
                    vars[k] = v

            # Update sec dict
            for oname, ovalue in nsections[rname].items():
                sections[rname][oname] += ' %s' % ovalue

        return meta, vars, sections, reqs

    meta, vars, sections, reqs = _read_config(filenames)

    return LibraryInfo(name=meta["name"], description=meta["description"],
            version=meta["version"], sections=sections, vars=VariableSet(vars))

# Trivial cache to cache LibraryInfo instances creation. To be really
# efficient, the cache should be handled in read_config, since a same file can
# be parsed many time outside LibraryInfo creation, but I doubt this will be a
# problem in practice
_CACHE = {}
def get_info(pkgname, dirs=None):
    try:
        return _CACHE[pkgname]
    except KeyError:
        v = read_config(pkg_to_filename(pkgname), dirs)
        _CACHE[pkgname] = v
        return v

# TODO:
#   - implements version comparison (modversion + atleast)

# pkg-config simple emulator - useful for debugging, and maybe later to query
# the system
if __name__ == '__main__':
    import sys
    from optparse import OptionParser
    import glob

    parser = OptionParser()
    parser.add_option("--cflags", dest="cflags", action="store_true",
                      help="output all preprocessor and compiler flags")
    parser.add_option("--libs", dest="libs", action="store_true",
                      help="output all linker flags")
    parser.add_option("--use-section", dest="section",
                      help="use this section instead of default for options")
    parser.add_option("--version", dest="version", action="store_true",
                      help="output version")
    parser.add_option("--atleast-version", dest="min_version",
                      help="Minimal version")
    parser.add_option("--list-all", dest="list_all", action="store_true",
                      help="Minimal version")
    parser.add_option("--define-variable", dest="define_variable",
                      help="Replace variable with the given value")

    (options, args) = parser.parse_args(sys.argv)

    if len(args) < 2:
        raise ValueError("Expect package name on the command line:")

    if options.list_all:
        files = glob.glob("*.ini")
        for f in files:
            info = read_config(f)
            print "%s\t%s - %s" % (info.name, info.name, info.description)

    pkg_name = args[1]
    info = get_info(pkg_name, ['numpy/distutils', '.'])

    if options.section:
        section = options.section
    else:
        section = "default"

    if options.define_variable:
        m = re.search('([\S]+)=([\S]+)', options.define_variable)
        if not m:
            raise ValueError("--define-variable option should be of " \
                             "the form --define-variable=foo=bar")
        else:
            name = m.group(1)
            value = m.group(2)
        info.vars[name] = value

    if options.cflags:
        print info.cflags(section)
    if options.libs:
        print info.libs(section)
    if options.version:
        print info.version
    if options.min_version:
        print info.version >= options.min_version
<commit_msg>Handle NPY_PKG_CONFIG_PATH in our fake pkg-config emulator.<commit_after>from ConfigParser import SafeConfigParser, NoOptionError
import re
import os

__all__ = ['FormatError', 'LibraryInfo', 'VariablesSet', 'get_info']

_VAR = re.compile('\$\{([a-zA-Z0-9_-]+)\}')

class FormatError(IOError):
    def __init__(self, msg):
        self.msg = msg

    def __str__(self):
        return self.msg

class LibraryInfo(object):
    def __init__(self, name, description, version, sections, vars, requires=None):
        self.name = name
        self.description = description
        if requires:
            self.requires = requires
        else:
            self.requires = []
        self.version = version
        self._sections = sections
        self.vars = vars

    def sections(self):
        return self._sections.keys()

    def cflags(self, section="default"):
        return self.vars.interpolate(self._sections[section]['cflags'])

    def libs(self, section="default"):
        return self.vars.interpolate(self._sections[section]['libs'])

    def __str__(self):
        m = ['Name: %s' % self.name]
        m.append('Description: %s' % self.description)
        if self.requires:
            m.append('Requires:')
        else:
            m.append('Requires: %s' % ",".join(self.requires))
        m.append('Version: %s' % self.version)

        return "\n".join(m)

class VariableSet(object):
    def __init__(self, d):
        self._raw_data = dict([(k, v) for k, v in d.items()])

        self._re = {}
        self._re_sub = {}

        self._init_parse()

    def _init_parse(self):
        for k, v in self._raw_data.items():
            self._init_parse_var(k, v)

    def _init_parse_var(self, name, value):
        self._re[name] = re.compile(r'\$\{%s\}' % name)
        self._re_sub[name] = value

    def interpolate(self, value):
        # Brute force: we keep interpolating until there is no '${var}' anymore
        # or until interpolated string is equal to input string
        def _interpolate(value):
            for k in self._re.keys():
                value = self._re[k].sub(self._re_sub[k], value)
            return value
        while _VAR.search(value):
            nvalue = _interpolate(value)
            if nvalue == value:
                break
            value = nvalue

        return value

    def variables(self):
        return self._raw_data.keys()

    # Emulate a dict to set/get variables values
    def __getitem__(self, name):
        return self._raw_data[name]

    def __setitem__(self, name, value):
        self._raw_data[name] = value
        self._init_parse_var(name, value)

def parse_meta(config):
    if not config.has_section('meta'):
        raise FormatError("No meta section found !")

    d = {}
    for name, value in config.items('meta'):
        d[name] = value

    for k in ['name', 'description', 'version']:
        if not d.has_key(k):
            raise FormatError("Option %s (section [meta]) is mandatory, "
                "but not found" % k)

    if not d.has_key('requires'):
        d['requires'] = []

    return d

def parse_variables(config):
    if not config.has_section('variables'):
        raise FormatError("No variables section found !")

    d = {}

    for name, value in config.items("variables"):
        d[name] = value

    return VariableSet(d)

def parse_sections(config):
    return meta_d, r

def pkg_to_filename(pkg_name):
    return "%s.ini" % pkg_name

def parse_config(filename, dirs=None):
    if dirs:
        filenames = [os.path.join(d, filename) for d in dirs]
    else:
        filenames = [filename]

    config = SafeConfigParser()
    n = config.read(filenames)
    if not len(n) >= 1:
        raise IOError("Could not find file(s) %s" % str(filenames))

    # Parse meta and variables sections
    meta = parse_meta(config)

    vars = {}
    if config.has_section('variables'):
        for name, value in config.items("variables"):
            vars[name] = value

    # Parse "normal" sections
    secs = [s for s in config.sections() if not s in ['meta', 'variables']]
    sections = {}

    requires = {}
    for s in secs:
        d = {}
        if config.has_option(s, "requires"):
            requires[s] = config.get(s, 'requires')

        for name, value in config.items(s):
            d[name] = value
        sections[s] = d

    return meta, vars, sections, requires

def read_config(filenames, dirs=None):
    def _read_config(f):
        meta, vars, sections, reqs = parse_config(f, dirs)
        # recursively add sections and variables of required libraries
        for rname, rvalue in reqs.items():
            nmeta, nvars, nsections, nreqs = _read_config(pkg_to_filename(rvalue))

            # Update var dict for variables not in 'top' config file
            for k, v in nvars.items():
                if not vars.has_key(k):
                    vars[k] = v

            # Update sec dict
            for oname, ovalue in nsections[rname].items():
                sections[rname][oname] += ' %s' % ovalue

        return meta, vars, sections, reqs

    meta, vars, sections, reqs = _read_config(filenames)

    return LibraryInfo(name=meta["name"], description=meta["description"],
            version=meta["version"], sections=sections, vars=VariableSet(vars))

# Trivial cache to cache LibraryInfo instances creation. To be really
# efficient, the cache should be handled in read_config, since a same file can
# be parsed many time outside LibraryInfo creation, but I doubt this will be a
# problem in practice
_CACHE = {}
def get_info(pkgname, dirs=None):
    try:
        return _CACHE[pkgname]
    except KeyError:
        v = read_config(pkg_to_filename(pkgname), dirs)
        _CACHE[pkgname] = v
        return v

# TODO:
#   - implements version comparison (modversion + atleast)

# pkg-config simple emulator - useful for debugging, and maybe later to query
# the system
if __name__ == '__main__':
    import sys
    from optparse import OptionParser
    import glob

    parser = OptionParser()
    parser.add_option("--cflags", dest="cflags", action="store_true",
                      help="output all preprocessor and compiler flags")
    parser.add_option("--libs", dest="libs", action="store_true",
                      help="output all linker flags")
    parser.add_option("--use-section", dest="section",
                      help="use this section instead of default for options")
    parser.add_option("--version", dest="version", action="store_true",
                      help="output version")
    parser.add_option("--atleast-version", dest="min_version",
                      help="Minimal version")
    parser.add_option("--list-all", dest="list_all", action="store_true",
                      help="Minimal version")
    parser.add_option("--define-variable", dest="define_variable",
                      help="Replace variable with the given value")

    (options, args) = parser.parse_args(sys.argv)

    if len(args) < 2:
        raise ValueError("Expect package name on the command line:")

    if options.list_all:
        files = glob.glob("*.ini")
        for f in files:
            info = read_config(f)
            print "%s\t%s - %s" % (info.name, info.name, info.description)

    pkg_name = args[1]
    import os
    d = os.environ.get('NPY_PKG_CONFIG_PATH')
    if d:
        info = get_info(pkg_name, ['numpy/distutils', '.', d])
    else:
        info = get_info(pkg_name, ['numpy/distutils', '.'])

    if options.section:
        section = options.section
    else:
        section = "default"

    if options.define_variable:
        m = re.search('([\S]+)=([\S]+)', options.define_variable)
        if not m:
            raise ValueError("--define-variable option should be of " \
                             "the form --define-variable=foo=bar")
        else:
            name = m.group(1)
            value = m.group(2)
        info.vars[name] = value

    if options.cflags:
        print info.cflags(section)
    if options.libs:
        print info.libs(section)
    if options.version:
        print info.version
    if options.min_version:
        print info.version >= options.min_version
<|endoftext|>


<commit_before># The MIT License (MIT)
#
# Copyright (c) 2016 Ivan Gavrilin
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.

# marker: see MPL doc

_SUPPORTED_ARGS = dict(marker=1, size=1, color=1, alpha=1, zorder=1)
_FLOAT_ARGS = dict(alpha=1, size=1)

class Channel:
    def __init__(self, stream, ax, **kw):
        self.stream = stream
        self.dirty = True
        self.datax = []
        self.datay = []
        self.axes = ax

        args = {}
        for k, v in kw.items():
            if not k in _SUPPORTED_ARGS:
                raise Exception("Scatter: unknown arg '{}'".format(k))
            if k in _FLOAT_ARGS:
                if k == 'size':
                    args['s'] = float(v) * float(v)
                else:
                    args[k] = float(v)
            else:
                args[k] = v

        self.artist = self.axes.scatter(self.datax, self.datay, **args)

    def prepare_artists(self):
        if not self.dirty:
            return False

        self.artist.set_offsets(list(zip(self.datax, self.datay)))

        self.dirty = False
        self.axes.relim()
        return True

    def destroy(self):
        if self.artist:
            self.artist.remove()

        self.artist = None
        self.stream = None

    def update_from_str(self, tm, line):

        if isinstance(tm, datetime.datetime):
            tm = tm.timestamp() * 1e6

        self.dirty = True
        self.datax.append(tm)
        self.datay.append(float(line))
        self.stream.invalidate()

<commit_msg>Bugfix: add forgotten import datetime<commit_after># The MIT License (MIT)
#
# Copyright (c) 2016 Ivan Gavrilin
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.

# marker: see MPL doc

import datetime

_SUPPORTED_ARGS = dict(marker=1, size=1, color=1, alpha=1, zorder=1)
_FLOAT_ARGS = dict(alpha=1, size=1)

class Channel:
    def __init__(self, stream, ax, **kw):
        self.stream = stream
        self.dirty = True
        self.datax = []
        self.datay = []
        self.axes = ax

        args = {}
        for k, v in kw.items():
            if not k in _SUPPORTED_ARGS:
                raise Exception("Scatter: unknown arg '{}'".format(k))
            if k in _FLOAT_ARGS:
                if k == 'size':
                    args['s'] = float(v) * float(v)
                else:
                    args[k] = float(v)
            else:
                args[k] = v

        self.artist = self.axes.scatter(self.datax, self.datay, **args)

    def prepare_artists(self):
        if not self.dirty:
            return False

        self.artist.set_offsets(list(zip(self.datax, self.datay)))

        self.dirty = False
        self.axes.relim()
        return True

    def destroy(self):
        if self.artist:
            self.artist.remove()

        self.artist = None
        self.stream = None

    def update_from_str(self, tm, line):

        if isinstance(tm, datetime.datetime):
            tm = tm.timestamp() * 1e6

        self.dirty = True
        self.datax.append(tm)
        self.datay.append(float(line))
        self.stream.invalidate()

<|endoftext|>