<commit_before>from itertools import product
import nose.tools as nt

import numpy as np
from scipy.stats import t as tdist
from scipy.stats import laplace, logistic, norm as ndist

from ..convenience import lasso, step, threshold
from ..query import optimization_sampler
from ...tests.instance import (gaussian_instance,
                               logistic_instance,
                               poisson_instance)
from ...tests.flags import SMALL_SAMPLES, SET_SEED
from ...tests.decorators import set_sampling_params_iftrue, set_seed_iftrue

from ...tests.decorators import set_sampling_params_iftrue
from ..randomization import randomization

class randomization_ppf(randomization):

    def __init__(self, rand, ppf):

        self._cdf = rand._cdf
        self._ppf = ppf
        self.shape = rand.shape

    @staticmethod
    def laplace(shape, scale):
        ppf = lambda x: laplace.ppf(x, loc=0, scale=scale)
        rand = randomization.laplace(shape, scale)
        return randomization_ppf(rand, ppf)

    @staticmethod
    def isotropic_gaussian(shape, scale):
        ppf = lambda x: ndist.ppf(x, loc=0., scale=scale)
        rand = randomization.isotropic_gaussian(shape, scale)
        return randomization_ppf(rand, ppf)

def inverse_truncated_cdf(x, lower, upper, randomization):
    arg = (randomization._cdf(lower) +
           np.multiply(x, randomization._cdf(upper) -
                       randomization._cdf(lower)))
    return randomization._ppf(arg)

def sampling_truncated_dist(lower, upper, randomization, nsamples=1000):
    uniform_samples = np.random.uniform(0,1, size=(nsamples,randomization.shape[0]))
    samples = np.zeros((nsamples, randomization.shape[0]))
    for i in range(nsamples):
        samples[i,:] = inverse_truncated_cdf(uniform_samples[i,:], lower, upper, randomization)
    return samples

def sample_opt_vars(X, y, active, signs, lam, epsilon, randomization, nsamples =10000):

    Xdiag = np.diag(X.T.dot(X))
    p = X.shape[1]
    nactive = active.sum()
    lower = np.zeros(p)
    upper = np.zeros(p)
    active_set = np.where(active)[0]

    for i in range(nactive):
        var = active_set[i]
        if signs[var]>0:
            lower[i] = (-X[:, var].T.dot(y) + lam * signs[var]) / Xdiag[var]
            upper[i] = np.inf
        else:
            lower[i] = -np.inf
            upper[i] = (-X[:,var].T.dot(y) + lam * signs[var]) / Xdiag[var]

    lower[range(nactive,p)] = -lam - X[:, ~active].T.dot(y)
    upper[range(nactive,p)] = lam - X[:, ~active].T.dot(y)

    omega_samples = sampling_truncated_dist(lower,
                                            upper,
                                            randomization,
                                            nsamples=nsamples)

    abs_beta_samples = np.true_divide(
                          omega_samples[:,:nactive] * Xdiag[active] +
                          X[:,active].T.dot(y)-
                          lam * signs[active],
                          (epsilon + Xdiag[active]) * signs[active])
    u_samples = omega_samples[:, nactive:] + X[:, ~active].T.dot(y)

    return np.concatenate((abs_beta_samples, u_samples), axis=1)

def orthogonal_design(n, p, s, signal, sigma, random_signs=True):
    scale = np.linspace(1, 1.2, p)
    X = np.identity(n)[:,:p]
    X *= scale[None, :]

    beta = np.zeros(p)
    signal = np.atleast_1d(signal)
    if signal.shape == (1,):
        beta[:s] = signal[0]
    else:
        beta[:s] = np.linspace(signal[0], signal[1], s)
    if random_signs:
        beta[:s] *= (2 * np.random.binomial(1, 0.5, size=(s,)) - 1.)
    np.random.shuffle(beta)

    active = np.zeros(p, np.bool)
    active[beta != 0] = True

    Y = (X.dot(beta) + np.random.standard_normal(n)) * sigma
    return X, Y, beta * sigma, np.nonzero(active)[0], sigma

@set_seed_iftrue(SET_SEED, 200)
@set_sampling_params_iftrue(SMALL_SAMPLES, ndraw=10, burnin=10)
def test_conditional_law(ndraw=20000, burnin=2000):
    """
    Checks the conditional law of opt variables given the data
    """

    results = []
    for const_info, rand in product(zip([gaussian_instance],
                                        [lasso.gaussian]),
                                    ['laplace', 'gaussian']):

        inst, const = const_info

        X, Y, beta = orthogonal_design(n=100,
                                       p=10,
                                       s=3,
                                       signal=(2,3),
                                       sigma=1.2)[:3]
        n, p = X.shape

        W = np.ones(X.shape[1]) * 1.2
        randomizer_scale =1.
        conv = const(X,
                     Y,
                     W,
                     randomizer=rand,
                     randomizer_scale=randomizer_scale)

        print(rand)
        if rand == "laplace":
            randomizer = randomization_ppf.laplace((p,), \
                             scale=randomizer_scale)
        elif rand=="gaussian":
            randomizer = randomization_ppf.isotropic_gaussian((p,), \
                             scale=randomizer_scale)

        signs = conv.fit()
        print("signs", signs)

        selected_features = conv._view.selection_variable['variables']

        conv._queries.setup_sampler(form_covariances=None)
        conv._queries.setup_opt_state()
        target_sampler = optimization_sampler(conv._queries)

        S = target_sampler.sample(ndraw,
                                  burnin,
                                  stepsize=None)
        print(S.shape)
        print([np.mean(S[:,i]) for i in range(p)])

        opt_samples = sample_opt_vars(X,
                                      Y,
                                      selected_features,
                                      signs,
                                      W[0],
                                      conv.ridge_term,
                                      randomizer,
                                      nsamples=ndraw)

        print([np.mean(opt_samples[:,i]) for i in range(p)])

        results.append((rand, S, opt_samples))

    return results

def plot_ecdf(ndraw=10000, burnin=1000):

    np.random.seed(20)

    import matplotlib.pyplot as plt
    from statsmodels.distributions import ECDF

    for (rand,
         mcmc,
         truncated) in test_conditional_law(ndraw=ndraw, burnin=burnin):

        fig = plt.figure(num=1, figsize=(8,15))
        plt.clf()
        idx = 0
        for i in range(mcmc.shape[1]):
            plt.subplot(5,2,idx+1)
            xval = np.linspace(min(mcmc[:,i].min(), truncated[:,i].min()),
                               max(mcmc[:,i].max(), truncated[:,i].max()),
                               200)
            plt.plot(xval, ECDF(mcmc[:,i])(xval), label='MCMC')
            plt.plot(xval, ECDF(truncated[:,i])(xval), label='truncated')
            idx += 1
            if idx == 1:
                plt.legend(loc='lower right')
        plt.savefig('fig%s.pdf' % rand)
    plt.show()

<commit_msg>BF: reconstruction<commit_after>from itertools import product
import nose.tools as nt

import numpy as np
from scipy.stats import t as tdist
from scipy.stats import laplace, logistic, norm as ndist

from ..convenience import lasso, step, threshold
from ..query import optimization_sampler
from ...tests.instance import (gaussian_instance,
                               logistic_instance,
                               poisson_instance)
from ...tests.flags import SMALL_SAMPLES, SET_SEED
from ...tests.decorators import set_sampling_params_iftrue, set_seed_iftrue

from ...tests.decorators import set_sampling_params_iftrue
from ..randomization import randomization

class randomization_ppf(randomization):

    def __init__(self, rand, ppf):

        self._cdf = rand._cdf
        self._ppf = ppf
        self.shape = rand.shape

    @staticmethod
    def laplace(shape, scale):
        ppf = lambda x: laplace.ppf(x, loc=0, scale=scale)
        rand = randomization.laplace(shape, scale)
        return randomization_ppf(rand, ppf)

    @staticmethod
    def isotropic_gaussian(shape, scale):
        ppf = lambda x: ndist.ppf(x, loc=0., scale=scale)
        rand = randomization.isotropic_gaussian(shape, scale)
        return randomization_ppf(rand, ppf)

def inverse_truncated_cdf(x, lower, upper, randomization):
    arg = (randomization._cdf(lower) +
           np.multiply(x, randomization._cdf(upper) -
                       randomization._cdf(lower)))
    return randomization._ppf(arg)

def sampling_truncated_dist(lower, upper, randomization, nsamples=1000):
    uniform_samples = np.random.uniform(0,1, size=(nsamples,randomization.shape[0]))
    samples = np.zeros((nsamples, randomization.shape[0]))
    for i in range(nsamples):
        samples[i,:] = inverse_truncated_cdf(uniform_samples[i,:], lower, upper, randomization)
    return samples

def sample_opt_vars(X, y, active, signs, lam, epsilon, randomization, nsamples =10000):

    Xdiag = np.diag(X.T.dot(X))
    p = X.shape[1]
    nactive = active.sum()
    lower = np.zeros(p)
    upper = np.zeros(p)
    active_set = np.where(active)[0]

    for i in range(nactive):
        var = active_set[i]
        if signs[var]>0:
            lower[i] = (-X[:, var].T.dot(y) + lam * signs[var])
            upper[i] = np.inf
        else:
            lower[i] = -np.inf
            upper[i] = (-X[:,var].T.dot(y) + lam * signs[var])

    lower[range(nactive,p)] = -lam - X[:, ~active].T.dot(y)
    upper[range(nactive,p)] = lam - X[:, ~active].T.dot(y)

    omega_samples = sampling_truncated_dist(lower,
                                            upper,
                                            randomization,
                                            nsamples=nsamples)

    abs_beta_samples = np.true_divide(
                          omega_samples[:,:nactive] +
                          X[:,active].T.dot(y) -
                          lam * signs[active],
                          (epsilon + Xdiag[active]) * signs[active])
    u_samples = omega_samples[:, nactive:] + X[:, ~active].T.dot(y)

    return np.concatenate((abs_beta_samples, u_samples), axis=1)

def orthogonal_design(n, p, s, signal, sigma, random_signs=True):
    scale = np.linspace(1, 1.2, p)
    X = np.identity(n)[:,:p]
    X *= scale[None, :]

    beta = np.zeros(p)
    signal = np.atleast_1d(signal)
    if signal.shape == (1,):
        beta[:s] = signal[0]
    else:
        beta[:s] = np.linspace(signal[0], signal[1], s)
    if random_signs:
        beta[:s] *= (2 * np.random.binomial(1, 0.5, size=(s,)) - 1.)
    np.random.shuffle(beta)

    active = np.zeros(p, np.bool)
    active[beta != 0] = True

    Y = (X.dot(beta) + np.random.standard_normal(n)) * sigma
    return X, Y, beta * sigma, np.nonzero(active)[0], sigma

@set_seed_iftrue(SET_SEED, 200)
@set_sampling_params_iftrue(SMALL_SAMPLES, ndraw=10, burnin=10)
def test_conditional_law(ndraw=20000, burnin=2000, epsilon=0.1):
    """
    Checks the conditional law of opt variables given the data
    """

    results = []
    for const_info, rand in product(zip([gaussian_instance],
                                        [lasso.gaussian]),
                                    ['laplace', 'gaussian']):

        inst, const = const_info

        X, Y, beta = orthogonal_design(n=100,
                                       p=9,
                                       s=3,
                                       signal=(2,3),
                                       sigma=1.2)[:3]
        n, p = X.shape

        W = np.ones(X.shape[1]) * 1.2
        randomizer_scale =1.
        conv = const(X,
                     Y,
                     W,
                     randomizer=rand,
                     randomizer_scale=randomizer_scale,
                     ridge_term=epsilon)

        print(rand)
        if rand == "laplace":
            randomizer = randomization_ppf.laplace((p,), \
                             scale=randomizer_scale)
        elif rand=="gaussian":
            randomizer = randomization_ppf.isotropic_gaussian((p,), \
                             scale=randomizer_scale)

        signs = conv.fit()
        print("signs", signs)

        selected_features = conv._view.selection_variable['variables']

        conv._queries.setup_sampler(form_covariances=None)
        conv._queries.setup_opt_state()
        target_sampler = optimization_sampler(conv._queries)

        S = target_sampler.sample(ndraw,
                                  burnin,
                                  stepsize=None)
        print(S.shape)
        print([np.mean(S[:,i]) for i in range(p)])

        opt_samples = sample_opt_vars(X,
                                      Y,
                                      selected_features,
                                      signs,
                                      W[0],
                                      conv.ridge_term,
                                      randomizer,
                                      nsamples=ndraw)

        print([np.mean(opt_samples[:,i]) for i in range(p)])

        results.append((rand, S, opt_samples))

    return results

def plot_ecdf(ndraw=10000, burnin=1000):

    np.random.seed(20)

    import matplotlib.pyplot as plt
    from statsmodels.distributions import ECDF

    for (rand,
         mcmc,
         truncated) in test_conditional_law(ndraw=ndraw, burnin=burnin):

        fig = plt.figure(num=1, figsize=(8,8))
        plt.clf()
        idx = 0
        for i in range(mcmc.shape[1]):
            plt.subplot(3,3,idx+1)
            xval = np.linspace(min(mcmc[:,i].min(), truncated[:,i].min()),
                               max(mcmc[:,i].max(), truncated[:,i].max()),
                               200)
            plt.plot(xval, ECDF(mcmc[:,i])(xval), label='MCMC')
            plt.plot(xval, ECDF(truncated[:,i])(xval), label='truncated')
            idx += 1
            if idx == 1:
                plt.legend(loc='lower right')
        plt.savefig('fig%s.pdf' % rand)
    plt.show()

<|endoftext|>


<commit_before># -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.

from lxml import etree

from odoo import api, models, fields

class FormatAddressMixin(models.AbstractModel):
    _inherit = "format.address.mixin"

    @api.model
    def fields_view_get_address(self, arch):
        arch = super(FormatAddressMixin, self).fields_view_get_address(arch)
        #render the partner address accordingly to address_view_id
        doc = etree.fromstring(arch)
        for city_node in doc.xpath("//field[@name='city']"):
            replacement_xml = """

            <field name="country_enforce_cities" invisible="1"/>

                <field name='city' attrs="{'invisible': ['|', ('city_id', '!=', False), ('city', '=', False)]}"/>
                <field name='city_id'/>

            """
            city_id_node = etree.fromstring(replacement_xml)
            city_node.getparent().replace(city_node, city_id_node)

        arch = etree.tostring(doc)
        return arch

class Partner(models.Model):
    _inherit = 'res.partner'

    country_enforce_cities = fields.Boolean(related='country_id.enforce_cities')
    city_id = fields.Many2one('res.city', string='Company')

    @api.onchange('city_id')
    def _onchange_city_id(self):
        self.city = self.city_id.name
        self.zip = self.city_id.zipcode
        self.state_id = self.city_id.state_id
<commit_msg>[FIX] base_address_city: _fields_view_get() now working properly<commit_after># -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.

from lxml import etree

from odoo import api, models, fields

class FormatAddressMixin(models.AbstractModel):
    _inherit = "format.address.mixin"

    @api.model
    def _fields_view_get_address(self, arch):
        arch = super(FormatAddressMixin, self)._fields_view_get_address(arch)
        #render the partner address accordingly to address_view_id
        doc = etree.fromstring(arch)
        for city_node in doc.xpath("//field[@name='city']"):
            replacement_xml = """

                <field name="country_enforce_cities" invisible="1"/>
                <field name='city' attrs="{'invisible': [('country_enforce_cities', '=', True), ('city_id', '!=', False)]}"/>
                <field name='city_id' attrs="{'invisible': [('country_enforce_cities', '=', False)]}"/>

            """
            city_id_node = etree.fromstring(replacement_xml)
            city_node.getparent().replace(city_node, city_id_node)

        arch = etree.tostring(doc)
        return arch

class Partner(models.Model):
    _inherit = 'res.partner'

    country_enforce_cities = fields.Boolean(related='country_id.enforce_cities')
    city_id = fields.Many2one('res.city', string='Company')

    @api.onchange('city_id')
    def _onchange_city_id(self):
        self.city = self.city_id.name
        self.zip = self.city_id.zipcode
        self.state_id = self.city_id.state_id
<|endoftext|>


<commit_before>import numpy as np
import numpy.testing.decorators as dec
from selection.constraints.affine import constraints
import statsmodels.api as sm

#@dec.slow()
def test_sequentially_constrained():
    S = -np.identity(10)[:3]
    b = -6 * np.ones(3)
    C = constraints(S, b)
    W = sample(C, 5000, temps=np.linspace(0, 200, 1001))
    U = np.linspace(0, 1, 101)
    D = sm.distributions.ECDF((ndist.cdf(W[0]) - ndist.cdf(6)) / ndist.sf(6))
    plt.plot(U, D(U))
<commit_msg>BF in test of sequential sampler<commit_after>import numpy as np
import numpy.testing.decorators as dec
from selection.constraints.affine import constraints
from selection.sampling.sequential import sample
from scipy.stats import norm as ndist
import statsmodels.api as sm

#@dec.slow()
def test_sequentially_constrained():
    S = -np.identity(10)[:3]
    b = -6 * np.ones(3)
    C = constraints(S, b)
    W = sample(C, 5000, temps=np.linspace(0, 200, 1001))
    U = np.linspace(0, 1, 101)
    D = sm.distributions.ECDF((ndist.cdf(W[0]) - ndist.cdf(6)) / ndist.sf(6))
    plt.plot(U, D(U))
<|endoftext|>


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

import mock
import six

from senlin.api.middleware import fault
from senlin.api.openstack.v1 import cluster_policies as cp_mod
from senlin.common import exception as senlin_exc
from senlin.common import policy
from senlin.rpc import client as rpc_client
from senlin.tests.apiv1 import shared
from senlin.tests.common import base

@mock.patch.object(policy, 'enforce')
class ClusterPolicyControllerTest(shared.ControllerTest, base.SenlinTestCase):
    '''Tests the API class which acts as the WSGI controller.'''

    def setUp(self):
        super(ClusterPolicyControllerTest, self).setUp()

        # Create WSGI controller instance
        class DummyConfig(object):
            bind_port = 8778

        cfgopts = DummyConfig()
        self.controller = cp_mod.ClusterPolicyController(options=cfgopts)

    def test_cluster_policy_index(self, mock_enforce):
        self._mock_enforce_setup(mock_enforce, 'index', True)
        cid = 'test_cluster'
        req = self._get('/cluster_policies/%s' % cid)

        engine_resp = [
            {
                'id': 'fake_id',
                'cluster_id': 'fake cluster id',
                'policy_id': 'fake policy id',
                'enabled': True,
                'cooldown': 60,
                'level': 30,
                'priority': 40,
                'data': {},
                'cluster_name': 'test_cluster',
                'policy_name': 'test_policy',
                'policy_type': 'ScalingPolicy',
            }
        ]

        mock_call = self.patchobject(rpc_client.EngineClient, 'call',
                                     return_value=engine_resp)

        result = self.controller.index(req, tenant_id=self.project,
                                       cluster_id=cid)

        default_args = {'sort_keys': None, 'sort_dir': None,
                        'filters': None, 'identity': cid}

        mock_call.assert_called_with(req.context,
                                     ('cluster_policy_list', default_args))

        expected = {'cluster_policies': engine_resp}
        self.assertEqual(expected, result)

    @mock.patch.object(rpc_client.EngineClient, 'call')
    def test_cluster_policy_index_whitelists_params(self, mock_call,
                                                    mock_enforce):
        self._mock_enforce_setup(mock_enforce, 'index', True)
        cid = 'FAKE_CLUSTER'
        params = {
            'sort_keys': 'fake sort keys',
            'sort_dir': 'fake sort dir',
            'filters': None,
            'balrog': 'you shall not pass!'
        }
        req = self._get('/cluster_policies/%s' % cid, params=params)
        mock_call.return_value = []

        self.controller.index(req, tenant_id=self.project, cluster_id=cid)

        rpc_call_args, _ = mock_call.call_args
        engine_args = rpc_call_args[1][1]

        self.assertEqual(4, len(engine_args))
        self.assertIn('sort_keys', engine_args)
        self.assertIn('sort_dir', engine_args)
        self.assertIn('filters', engine_args)
        self.assertNotIn('balrog', engine_args)

    @mock.patch.object(rpc_client.EngineClient, 'call')
    def test_cluster_policy_index_whitelist_filter_params(self, mock_call,
                                                          mock_enforce):
        self._mock_enforce_setup(mock_enforce, 'index', True)
        cid = 'FAKE_CLUSTER'
        params = {
            'priority': 20,
            'level': 50,
            'balrog': 'you shall not pass!'
        }
        req = self._get('/cluster_policies/%s' % cid, params=params)
        mock_call.return_value = []

        self.controller.index(req, tenant_id=self.project, cluster_id=cid)

        rpc_call_args, _ = mock_call.call_args
        engine_args = rpc_call_args[1][1]
        self.assertIn('filters', engine_args)

        filters = engine_args['filters']
        self.assertEqual(2, len(filters))
        self.assertIn('priority', filters)
        self.assertIn('level', filters)
        self.assertNotIn('balrog', filters)

    def test_cluster_policy_index_denied_policy(self, mock_enforce):
        self._mock_enforce_setup(mock_enforce, 'index', False)
        cid = 'FAKE_CLUSTER'
        req = self._get('/cluster_policy/%s' % cid)

        resp = shared.request_with_middleware(fault.FaultWrapper,
                                              self.controller.index,
                                              req, tenant_id=self.project,
                                              cluster_id=cid)

        self.assertEqual(403, resp.status_int)
        self.assertIn('403 Forbidden', six.text_type(resp))

    def test_cluster_policy_get_success(self, mock_enforce):
        self._mock_enforce_setup(mock_enforce, 'get', True)
        cid = 'FAKE_CLUSTER'
        pid = 'FAKE_POLICY'
        req = self._get('/cluster_policies/%(cid)s/%(pid)s'
                        '' % {'cid': cid, 'pid': pid})

        engine_resp = {
            'id': 'fake_id',
            'cluster_id': cid,
            'policy_id': pid,
            'enabled': True,
            'cooldown': 60,
            'level': 30,
            'priority': 40,
            'data': {},
            'cluster_name': 'test_cluster',
            'policy_name': 'test_policy',
            'policy_type': 'ScalingPolicy',
        }

        mock_call = self.patchobject(rpc_client.EngineClient, 'call',
                                     return_value=engine_resp)
        response = self.controller.get(req, tenant_id=self.project,
                                       cluster_id=cid,
                                       policy_id=pid)

        mock_call.assert_called_once_with(
            req.context, ('cluster_policy_get',
                          {'identity': cid, 'policy_id': pid}))

        self.assertEqual({'cluster_policy': engine_resp}, response)

    def test_cluster_policy_get_not_found(self, mock_enforce):
        self._mock_enforce_setup(mock_enforce, 'get', True)
        cid = 'FAKE_CLUSTER'
        pid = 'FAKE_POLICY'
        req = self._get('/cluster_policies/%(cid)s/%(pid)s'
                        '' % {'cid': cid, 'pid': pid})

        error = senlin_exc.PolicyBindingNotFound(policy=pid, identity=cid)
        mock_call = self.patchobject(rpc_client.EngineClient, 'call')
        mock_call.side_effect = shared.to_remote_error(error)

        resp = shared.request_with_middleware(fault.FaultWrapper,
                                              self.controller.get,
                                              req, tenant_id=self.project,
                                              cluster_id=cid, policy_id=pid)

        self.assertEqual(404, resp.json['code'])
        self.assertEqual('PolicyBindingNotFound', resp.json['error']['type'])

    def test_action_get_denied_policy(self, mock_enforce):
        self._mock_enforce_setup(mock_enforce, 'get', False)
        cid = 'FAKE_CLUSTER'
        pid = 'FAKE_POLICY'
        req = self._get('/cluster_policies/%(cid)s/%(pid)s'
                        '' % {'cid': cid, 'pid': pid})

        resp = shared.request_with_middleware(fault.FaultWrapper,
                                              self.controller.get,
                                              req, tenant_id=self.project,
                                              cluster_id=cid, policy_id=pid)

        self.assertEqual(403, resp.status_int)
        self.assertIn('403 Forbidden', six.text_type(resp))
<commit_msg>Test case for default handler in cluster_policies API<commit_after># Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
#         http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.

import mock
import six
from webob import exc

from senlin.api.middleware import fault
from senlin.api.openstack.v1 import cluster_policies as cp_mod
from senlin.common import exception as senlin_exc
from senlin.common import policy
from senlin.rpc import client as rpc_client
from senlin.tests.apiv1 import shared
from senlin.tests.common import base

@mock.patch.object(policy, 'enforce')
class ClusterPolicyControllerTest(shared.ControllerTest, base.SenlinTestCase):
    '''Tests the API class which acts as the WSGI controller.'''

    def setUp(self):
        super(ClusterPolicyControllerTest, self).setUp()

        # Create WSGI controller instance
        class DummyConfig(object):
            bind_port = 8778

        cfgopts = DummyConfig()
        self.controller = cp_mod.ClusterPolicyController(options=cfgopts)

    def test_default(self, mock_enforce):
        self.assertRaises(exc.HTTPNotFound, self.controller.default, None)

    def test_cluster_policy_index(self, mock_enforce):
        self._mock_enforce_setup(mock_enforce, 'index', True)
        cid = 'test_cluster'
        req = self._get('/cluster_policies/%s' % cid)

        engine_resp = [
            {
                'id': 'fake_id',
                'cluster_id': 'fake cluster id',
                'policy_id': 'fake policy id',
                'enabled': True,
                'cooldown': 60,
                'level': 30,
                'priority': 40,
                'data': {},
                'cluster_name': 'test_cluster',
                'policy_name': 'test_policy',
                'policy_type': 'ScalingPolicy',
            }
        ]

        mock_call = self.patchobject(rpc_client.EngineClient, 'call',
                                     return_value=engine_resp)

        result = self.controller.index(req, tenant_id=self.project,
                                       cluster_id=cid)

        default_args = {'sort_keys': None, 'sort_dir': None,
                        'filters': None, 'identity': cid}

        mock_call.assert_called_with(req.context,
                                     ('cluster_policy_list', default_args))

        expected = {'cluster_policies': engine_resp}
        self.assertEqual(expected, result)

    @mock.patch.object(rpc_client.EngineClient, 'call')
    def test_cluster_policy_index_whitelists_params(self, mock_call,
                                                    mock_enforce):
        self._mock_enforce_setup(mock_enforce, 'index', True)
        cid = 'FAKE_CLUSTER'
        params = {
            'sort_keys': 'fake sort keys',
            'sort_dir': 'fake sort dir',
            'filters': None,
            'balrog': 'you shall not pass!'
        }
        req = self._get('/cluster_policies/%s' % cid, params=params)
        mock_call.return_value = []

        self.controller.index(req, tenant_id=self.project, cluster_id=cid)

        rpc_call_args, _ = mock_call.call_args
        engine_args = rpc_call_args[1][1]

        self.assertEqual(4, len(engine_args))
        self.assertIn('sort_keys', engine_args)
        self.assertIn('sort_dir', engine_args)
        self.assertIn('filters', engine_args)
        self.assertNotIn('balrog', engine_args)

    @mock.patch.object(rpc_client.EngineClient, 'call')
    def test_cluster_policy_index_whitelist_filter_params(self, mock_call,
                                                          mock_enforce):
        self._mock_enforce_setup(mock_enforce, 'index', True)
        cid = 'FAKE_CLUSTER'
        params = {
            'priority': 20,
            'level': 50,
            'balrog': 'you shall not pass!'
        }
        req = self._get('/cluster_policies/%s' % cid, params=params)
        mock_call.return_value = []

        self.controller.index(req, tenant_id=self.project, cluster_id=cid)

        rpc_call_args, _ = mock_call.call_args
        engine_args = rpc_call_args[1][1]
        self.assertIn('filters', engine_args)

        filters = engine_args['filters']
        self.assertEqual(2, len(filters))
        self.assertIn('priority', filters)
        self.assertIn('level', filters)
        self.assertNotIn('balrog', filters)

    def test_cluster_policy_index_denied_policy(self, mock_enforce):
        self._mock_enforce_setup(mock_enforce, 'index', False)
        cid = 'FAKE_CLUSTER'
        req = self._get('/cluster_policy/%s' % cid)

        resp = shared.request_with_middleware(fault.FaultWrapper,
                                              self.controller.index,
                                              req, tenant_id=self.project,
                                              cluster_id=cid)

        self.assertEqual(403, resp.status_int)
        self.assertIn('403 Forbidden', six.text_type(resp))

    def test_cluster_policy_get_success(self, mock_enforce):
        self._mock_enforce_setup(mock_enforce, 'get', True)
        cid = 'FAKE_CLUSTER'
        pid = 'FAKE_POLICY'
        req = self._get('/cluster_policies/%(cid)s/%(pid)s'
                        '' % {'cid': cid, 'pid': pid})

        engine_resp = {
            'id': 'fake_id',
            'cluster_id': cid,
            'policy_id': pid,
            'enabled': True,
            'cooldown': 60,
            'level': 30,
            'priority': 40,
            'data': {},
            'cluster_name': 'test_cluster',
            'policy_name': 'test_policy',
            'policy_type': 'ScalingPolicy',
        }

        mock_call = self.patchobject(rpc_client.EngineClient, 'call',
                                     return_value=engine_resp)
        response = self.controller.get(req, tenant_id=self.project,
                                       cluster_id=cid,
                                       policy_id=pid)

        mock_call.assert_called_once_with(
            req.context, ('cluster_policy_get',
                          {'identity': cid, 'policy_id': pid}))

        self.assertEqual({'cluster_policy': engine_resp}, response)

    def test_cluster_policy_get_not_found(self, mock_enforce):
        self._mock_enforce_setup(mock_enforce, 'get', True)
        cid = 'FAKE_CLUSTER'
        pid = 'FAKE_POLICY'
        req = self._get('/cluster_policies/%(cid)s/%(pid)s'
                        '' % {'cid': cid, 'pid': pid})

        error = senlin_exc.PolicyBindingNotFound(policy=pid, identity=cid)
        mock_call = self.patchobject(rpc_client.EngineClient, 'call')
        mock_call.side_effect = shared.to_remote_error(error)

        resp = shared.request_with_middleware(fault.FaultWrapper,
                                              self.controller.get,
                                              req, tenant_id=self.project,
                                              cluster_id=cid, policy_id=pid)

        self.assertEqual(404, resp.json['code'])
        self.assertEqual('PolicyBindingNotFound', resp.json['error']['type'])

    def test_action_get_denied_policy(self, mock_enforce):
        self._mock_enforce_setup(mock_enforce, 'get', False)
        cid = 'FAKE_CLUSTER'
        pid = 'FAKE_POLICY'
        req = self._get('/cluster_policies/%(cid)s/%(pid)s'
                        '' % {'cid': cid, 'pid': pid})

        resp = shared.request_with_middleware(fault.FaultWrapper,
                                              self.controller.get,
                                              req, tenant_id=self.project,
                                              cluster_id=cid, policy_id=pid)

        self.assertEqual(403, resp.status_int)
        self.assertIn('403 Forbidden', six.text_type(resp))
<|endoftext|>


<commit_before>import discord
import asyncio
import random
import json
import time
import cleverbot
import requests
import git
import subprocess
import sys
import os
import logging
import uvloop
import aiohttp
from datetime import datetime
import modules.commands as commands
import modules.botToken as botToken
from google import search

asyncio.set_event_loop_policy(uvloop.EventLoopPolicy())

logging.basicConfig(level=logging.INFO)

with open("prefix.json", "r") as infile:
    prefix = json.loads(infile.read())

with open("quoteweenie.json","r") as infile:
    Quotes_All = json.loads(infile.read())

with open("adminweenie.json","r") as infile:
    admin = json.loads(infile.read())

with open("quoteweenie.json", "w+") as outfile:
    outfile.write(json.dumps(Quotes_All))

with open("adminweenie.json", "w+") as outfile:
    outfile.write(json.dumps(admin))

with open("prefix.json", "w+") as outfile:
    outfile.write(json.dumps(prefix))

class Weenie(discord.Client):
    def __init__(self, *args, **kwargs):
        self.timer = 0
        self.suspend = False
        super().__init__(*args, **kwargs)

status = {
    'online': 'Online',
    'offline': 'Offline',
    'idle': 'Idle',
    'dnd': 'Do Not Disturb'
}

x33 = '%m-%d-%Y'
client = Weenie()
cb1 = commands.cb1
gamet = discord.Game(name='beefywhale.github.io/WeenieBot/')
def bdel(s, r): return (s[len(r):] if s.startswith(r) else s)

@client.event
async def on_ready():
    print('Logged in as')
    print(client.user.name)
    print(client.user.id)
    print('<Servers>')
    for server in client.servers:
        print(server)
    print('------')
    await client.change_presence(game=gamet, status='online', afk=False)
    try:
        await client.change_nickname(message.server.me, 'WeenieBot')
    except:
        pass

@client.event
async def on_member_join(member):
    if member.server.id != '110373943822540800':
        await client.send_message(member.server.default_channel, "{0.mention} has joined {0.server.name} give them a warm welcome!".format(member))

@client.event
async def on_message(message):
    with open("database/prefixMap.json", "r") as infile:
        prefixMap = json.loads(infile.read())
    if message.server.id not in prefixMap:
        prefixMap[message.server.id] = '!'
        client.pfix = prefixMap[message.server.id]
    else:
        client.pfix = prefixMap[message.server.id]

    if message.content.startswith(client.pfix)  and client.suspend == False:
        try:
            if message.content == client.pfix + 'quote' :
                await commands.rand_quote(message, client)
            elif message.content.split(' ')[0] == client.pfix + 'quote':
                await commands.quote_logic(message, client)
            else:
                cmd = bdel(message.content.lower(), client.pfix)
                cmd = cmd.split(' ')
                await commands.cmdDict[cmd[0]](message, client)
        except KeyError as e:
            print(str(e) + ' No command')

    if message.content.lower().startswith('weeniebot'):
        await commands.cleverbot_logic(message, client)
    elif message.content.lower().startswith('wb'):
        await commands.cleverbot_logictwo(message, client)

    if message.content == client.pfix + 'resume' and client.suspend == True:
        await commands.resume_logic(message, client)

    if message.content == "prefix":
        await commands.get_prefix(message, client)

    if message.content == client.pfix + 'jfgi':
        await client.send_message(message.channel, 'http://www.justfuckinggoogleit.com/')

    if message.content == client.pfix + 'good?':
        await client.send_message(message.channel, 'I am as Fit as a Fiddle!')

    if message.content == client.pfix + 'turtles':
        await client.send_message(message.channel, 'https://www.youtube.com/watch?v=o4PBYRN-ndI')

    if message.content.lower() == 'hello weeniebot':
        await client.send_message(message.channel, message.author.mention + ' ' + 'Hello! I am WeenieBot, your robot friend, here to help you with your needs on this server! type ' + pfix + 'help to see what I can do for you!')

client.run(botToken.token)

<commit_msg>Error handling for Welcome message<commit_after>import discord
import asyncio
import random
import json
import time
import cleverbot
import requests
import git
import subprocess
import sys
import os
import logging
import uvloop
import aiohttp
from datetime import datetime
import modules.commands as commands
import modules.botToken as botToken
from google import search

asyncio.set_event_loop_policy(uvloop.EventLoopPolicy())

logging.basicConfig(level=logging.INFO)

with open("prefix.json", "r") as infile:
    prefix = json.loads(infile.read())

with open("quoteweenie.json","r") as infile:
    Quotes_All = json.loads(infile.read())

with open("adminweenie.json","r") as infile:
    admin = json.loads(infile.read())

with open("quoteweenie.json", "w+") as outfile:
    outfile.write(json.dumps(Quotes_All))

with open("adminweenie.json", "w+") as outfile:
    outfile.write(json.dumps(admin))

with open("prefix.json", "w+") as outfile:
    outfile.write(json.dumps(prefix))

class Weenie(discord.Client):
    def __init__(self, *args, **kwargs):
        self.timer = 0
        self.suspend = False
        super().__init__(*args, **kwargs)

status = {
    'online': 'Online',
    'offline': 'Offline',
    'idle': 'Idle',
    'dnd': 'Do Not Disturb'
}

x33 = '%m-%d-%Y'
client = Weenie()
cb1 = commands.cb1
gamet = discord.Game(name='beefywhale.github.io/WeenieBot/')
def bdel(s, r): return (s[len(r):] if s.startswith(r) else s)

@client.event
async def on_ready():
    print('Logged in as')
    print(client.user.name)
    print(client.user.id)
    print('<Servers>')
    for server in client.servers:
        print(server)
    print('------')
    await client.change_presence(game=gamet, status='online', afk=False)
    try:
        await client.change_nickname(message.server.me, 'WeenieBot')
    except:
        pass

@client.event
async def on_member_join(member):
    if member.server.id != '110373943822540800':
        try:
            await client.send_message(member.server.default_channel, "{0.mention} has joined {0.server.name} give them a warm welcome!".format(member))
        except discord.Forbidden:
            print('Couldn\'t welcome {} in server {} do to perms error.'.format(member, member.server))

@client.event
async def on_message(message):
    with open("database/prefixMap.json", "r") as infile:
        prefixMap = json.loads(infile.read())
    if message.server.id not in prefixMap:
        prefixMap[message.server.id] = '!'
        client.pfix = prefixMap[message.server.id]
    else:
        client.pfix = prefixMap[message.server.id]

    if message.content.startswith(client.pfix)  and client.suspend == False:
        try:
            if message.content == client.pfix + 'quote' :
                await commands.rand_quote(message, client)
            elif message.content.split(' ')[0] == client.pfix + 'quote':
                await commands.quote_logic(message, client)
            else:
                cmd = bdel(message.content.lower(), client.pfix)
                cmd = cmd.split(' ')
                await commands.cmdDict[cmd[0]](message, client)
        except KeyError as e:
            print(str(e) + ' No command')

    if message.content.lower().startswith('weeniebot'):
        await commands.cleverbot_logic(message, client)
    elif message.content.lower().startswith('wb'):
        await commands.cleverbot_logictwo(message, client)

    if message.content == client.pfix + 'resume' and client.suspend == True:
        await commands.resume_logic(message, client)

    if message.content == "prefix":
        await commands.get_prefix(message, client)

    if message.content == client.pfix + 'jfgi':
        await client.send_message(message.channel, 'http://www.justfuckinggoogleit.com/')

    if message.content == client.pfix + 'good?':
        await client.send_message(message.channel, 'I am as Fit as a Fiddle!')

    if message.content == client.pfix + 'turtles':
        await client.send_message(message.channel, 'https://www.youtube.com/watch?v=o4PBYRN-ndI')

    if message.content.lower() == 'hello weeniebot':
        await client.send_message(message.channel, message.author.mention + ' ' + 'Hello! I am WeenieBot, your robot friend, here to help you with your needs on this server! type ' + pfix + 'help to see what I can do for you!')

client.run(botToken.token)

<|endoftext|>


<commit_before>import collections
from math import ceil

from django.utils import six

class InvalidPage(Exception):
    pass

class PageNotAnInteger(InvalidPage):
    pass

class EmptyPage(InvalidPage):
    pass

class Paginator(object):

    def __init__(self, object_list, per_page, orphans=0,
                 allow_empty_first_page=True):
        self.object_list = object_list
        self.per_page = int(per_page)
        self.orphans = int(orphans)
        self.allow_empty_first_page = allow_empty_first_page
        self._num_pages = self._count = None

    def validate_number(self, number):
        """
        Validates the given 1-based page number.
        """
        try:
            number = int(number)
        except (TypeError, ValueError):
            raise PageNotAnInteger('That page number is not an integer')
        if number < 1:
            raise EmptyPage('That page number is less than 1')
        if number > self.num_pages:
            if number == 1 and self.allow_empty_first_page:
                pass
            else:
                raise EmptyPage('That page contains no results')
        return number

    def page(self, number):
        """
        Returns a Page object for the given 1-based page number.
        """
        number = self.validate_number(number)
        bottom = (number - 1) * self.per_page
        top = bottom + self.per_page
        if top + self.orphans >= self.count:
            top = self.count
        return self._get_page(self.object_list[bottom:top], number, self)

    def _get_page(self, *args, **kwargs):
        """
        Returns an instance of a single page.

        This hook can be used by subclasses to use an alternative to the
        standard :cls:`Page` object.
        """
        return Page(*args, **kwargs)

    def _get_count(self):
        """
        Returns the total number of objects, across all pages.
        """
        if self._count is None:
            try:
                self._count = self.object_list.count()
            except (AttributeError, TypeError):
                # AttributeError if object_list has no count() method.
                # TypeError if object_list.count() requires arguments
                # (i.e. is of type list).
                self._count = len(self.object_list)
        return self._count
    count = property(_get_count)

    def _get_num_pages(self):
        """
        Returns the total number of pages.
        """
        if self._num_pages is None:
            if self.count == 0 and not self.allow_empty_first_page:
                self._num_pages = 0
            else:
                hits = max(1, self.count - self.orphans)
                self._num_pages = int(ceil(hits / float(self.per_page)))
        return self._num_pages
    num_pages = property(_get_num_pages)

    def _get_page_range(self):
        """
        Returns a 1-based range of pages for iterating through within
        a template for loop.
        """
        return range(1, self.num_pages + 1)
    page_range = property(_get_page_range)

QuerySetPaginator = Paginator   # For backwards-compatibility.

class Page(collections.Sequence):

    def __init__(self, object_list, number, paginator):
        self.object_list = object_list
        self.number = number
        self.paginator = paginator

    def __repr__(self):
        return '<Page %s of %s>' % (self.number, self.paginator.num_pages)

    def __len__(self):
        return len(self.object_list)

    def __getitem__(self, index):
        if not isinstance(index, (slice,) + six.integer_types):
            raise TypeError
        # The object_list is converted to a list so that if it was a QuerySet
        # it won't be a database hit per __getitem__.
        if not isinstance(self.object_list, list):
            self.object_list = list(self.object_list)
        return self.object_list[index]

    def has_next(self):
        return self.number < self.paginator.num_pages

    def has_previous(self):
        return self.number > 1

    def has_other_pages(self):
        return self.has_previous() or self.has_next()

    def next_page_number(self):
        return self.paginator.validate_number(self.number + 1)

    def previous_page_number(self):
        return self.paginator.validate_number(self.number - 1)

    def start_index(self):
        """
        Returns the 1-based index of the first object on this page,
        relative to total objects in the paginator.
        """
        # Special case, return zero if no items.
        if self.paginator.count == 0:
            return 0
        return (self.paginator.per_page * (self.number - 1)) + 1

    def end_index(self):
        """
        Returns the 1-based index of the last object on this page,
        relative to total objects found (hits).
        """
        # Special case for the last page because there can be orphans.
        if self.number == self.paginator.num_pages:
            return self.paginator.count
        return self.number * self.paginator.per_page
<commit_msg>[1.7.x] Ensured that Paginator.page_range works the same on Python 2 and 3.<commit_after>import collections
from math import ceil

from django.utils import six

class InvalidPage(Exception):
    pass

class PageNotAnInteger(InvalidPage):
    pass

class EmptyPage(InvalidPage):
    pass

class Paginator(object):

    def __init__(self, object_list, per_page, orphans=0,
                 allow_empty_first_page=True):
        self.object_list = object_list
        self.per_page = int(per_page)
        self.orphans = int(orphans)
        self.allow_empty_first_page = allow_empty_first_page
        self._num_pages = self._count = None

    def validate_number(self, number):
        """
        Validates the given 1-based page number.
        """
        try:
            number = int(number)
        except (TypeError, ValueError):
            raise PageNotAnInteger('That page number is not an integer')
        if number < 1:
            raise EmptyPage('That page number is less than 1')
        if number > self.num_pages:
            if number == 1 and self.allow_empty_first_page:
                pass
            else:
                raise EmptyPage('That page contains no results')
        return number

    def page(self, number):
        """
        Returns a Page object for the given 1-based page number.
        """
        number = self.validate_number(number)
        bottom = (number - 1) * self.per_page
        top = bottom + self.per_page
        if top + self.orphans >= self.count:
            top = self.count
        return self._get_page(self.object_list[bottom:top], number, self)

    def _get_page(self, *args, **kwargs):
        """
        Returns an instance of a single page.

        This hook can be used by subclasses to use an alternative to the
        standard :cls:`Page` object.
        """
        return Page(*args, **kwargs)

    def _get_count(self):
        """
        Returns the total number of objects, across all pages.
        """
        if self._count is None:
            try:
                self._count = self.object_list.count()
            except (AttributeError, TypeError):
                # AttributeError if object_list has no count() method.
                # TypeError if object_list.count() requires arguments
                # (i.e. is of type list).
                self._count = len(self.object_list)
        return self._count
    count = property(_get_count)

    def _get_num_pages(self):
        """
        Returns the total number of pages.
        """
        if self._num_pages is None:
            if self.count == 0 and not self.allow_empty_first_page:
                self._num_pages = 0
            else:
                hits = max(1, self.count - self.orphans)
                self._num_pages = int(ceil(hits / float(self.per_page)))
        return self._num_pages
    num_pages = property(_get_num_pages)

    def _get_page_range(self):
        """
        Returns a 1-based range of pages for iterating through within
        a template for loop.
        """
        return list(six.moves.range(1, self.num_pages + 1))
    page_range = property(_get_page_range)

QuerySetPaginator = Paginator   # For backwards-compatibility.

class Page(collections.Sequence):

    def __init__(self, object_list, number, paginator):
        self.object_list = object_list
        self.number = number
        self.paginator = paginator

    def __repr__(self):
        return '<Page %s of %s>' % (self.number, self.paginator.num_pages)

    def __len__(self):
        return len(self.object_list)

    def __getitem__(self, index):
        if not isinstance(index, (slice,) + six.integer_types):
            raise TypeError
        # The object_list is converted to a list so that if it was a QuerySet
        # it won't be a database hit per __getitem__.
        if not isinstance(self.object_list, list):
            self.object_list = list(self.object_list)
        return self.object_list[index]

    def has_next(self):
        return self.number < self.paginator.num_pages

    def has_previous(self):
        return self.number > 1

    def has_other_pages(self):
        return self.has_previous() or self.has_next()

    def next_page_number(self):
        return self.paginator.validate_number(self.number + 1)

    def previous_page_number(self):
        return self.paginator.validate_number(self.number - 1)

    def start_index(self):
        """
        Returns the 1-based index of the first object on this page,
        relative to total objects in the paginator.
        """
        # Special case, return zero if no items.
        if self.paginator.count == 0:
            return 0
        return (self.paginator.per_page * (self.number - 1)) + 1

    def end_index(self):
        """
        Returns the 1-based index of the last object on this page,
        relative to total objects found (hits).
        """
        # Special case for the last page because there can be orphans.
        if self.number == self.paginator.num_pages:
            return self.paginator.count
        return self.number * self.paginator.per_page
<|endoftext|>


<commit_before># coding:utf-8
from base import TestBase
import sublime
import sys

class TestListBullets(TestBase):
    """Test of attributes 'bullets'"""

    # for debug
    # def tearDown(self):
    #     pass

    bullets_text = \
"""

<!-- MarkdownTOC levels="1,2,3,4,5,6" {0} -->

<!-- /MarkdownTOC -->

# Heading1
## Heading2
## Heading2-2
### Heading3
### Heading3-2
#### Heading4
#### Heading4-2
##### Heading5
###### Heading6
"""
    def test_bullets_default(self):
        toc_txt = self.commonSetup(self.bullets_text.format(''))
        self.assert_In('- Heading1', toc_txt)
        self.assert_In('- Heading2', toc_txt)
        self.assert_In('- Heading2-2', toc_txt)
        self.assert_In('- Heading3', toc_txt)
        self.assert_In('- Heading3-2', toc_txt)
        self.assert_In('- Heading4', toc_txt)
        self.assert_In('- Heading4-2', toc_txt)
        self.assert_In('- Heading5', toc_txt)
        self.assert_In('- Heading6', toc_txt)
    def test_bullets_2values(self):
        toc_txt = self.commonSetup(self.bullets_text.format('bullets="+,-"'))
        self.assert_In('+ Heading1', toc_txt)
        self.assert_In('- Heading2', toc_txt)
        self.assert_In('- Heading2-2', toc_txt)
        self.assert_In('+ Heading3', toc_txt)
        self.assert_In('+ Heading3-2', toc_txt)
        self.assert_In('- Heading4', toc_txt)
        self.assert_In('- Heading4-2', toc_txt)
        self.assert_In('+ Heading5', toc_txt)
        self.assert_In('- Heading6', toc_txt)
    def test_bullets_3values(self):
        toc_txt = self.commonSetup(self.bullets_text.format('bullets="-,+,*"'))
        self.assert_In('- Heading1', toc_txt)
        self.assert_In('+ Heading2', toc_txt)
        self.assert_In('+ Heading2-2', toc_txt)
        self.assert_In('* Heading3', toc_txt)
        self.assert_In('* Heading3-2', toc_txt)
        self.assert_In('- Heading4', toc_txt)
        self.assert_In('- Heading4-2', toc_txt)
        self.assert_In('+ Heading5', toc_txt)
        self.assert_In('* Heading6', toc_txt)
    def test_bullets_4values(self):
        toc_txt = self.commonSetup(self.bullets_text.format('bullets="-,+,-,*"'))
        self.assert_In('- Heading1', toc_txt)
        self.assert_In('+ Heading2', toc_txt)
        self.assert_In('+ Heading2-2', toc_txt)
        self.assert_In('- Heading3', toc_txt)
        self.assert_In('- Heading3-2', toc_txt)
        self.assert_In('* Heading4', toc_txt)
        self.assert_In('* Heading4-2', toc_txt)
        self.assert_In('- Heading5', toc_txt)
        self.assert_In('+ Heading6', toc_txt)<commit_msg>Cleanup<commit_after># coding:utf-8
from base import TestBase
import sublime
import sys

class TestListBullets(TestBase):
    """Test of attributes 'bullets'"""

    # for debug
    # def tearDown(self):
    #     pass

    bullets_text = \
"""

<!-- MarkdownTOC levels="1,2,3,4,5,6" {0} -->

<!-- /MarkdownTOC -->

# Heading1
## Heading2
## Heading2-2
### Heading3
### Heading3-2
#### Heading4
#### Heading4-2
##### Heading5
###### Heading6
"""

    def test_bullets_default(self):
        toc_txt = self.commonSetup(self.bullets_text.format(''))
        self.assert_In('- Heading1', toc_txt)
        self.assert_In('- Heading2', toc_txt)
        self.assert_In('- Heading2-2', toc_txt)
        self.assert_In('- Heading3', toc_txt)
        self.assert_In('- Heading3-2', toc_txt)
        self.assert_In('- Heading4', toc_txt)
        self.assert_In('- Heading4-2', toc_txt)
        self.assert_In('- Heading5', toc_txt)
        self.assert_In('- Heading6', toc_txt)
    def test_bullets_2values(self):
        toc_txt = self.commonSetup(self.bullets_text.format('bullets="+,-"'))
        self.assert_In('+ Heading1', toc_txt)
        self.assert_In('- Heading2', toc_txt)
        self.assert_In('- Heading2-2', toc_txt)
        self.assert_In('+ Heading3', toc_txt)
        self.assert_In('+ Heading3-2', toc_txt)
        self.assert_In('- Heading4', toc_txt)
        self.assert_In('- Heading4-2', toc_txt)
        self.assert_In('+ Heading5', toc_txt)
        self.assert_In('- Heading6', toc_txt)
    def test_bullets_3values(self):
        toc_txt = self.commonSetup(self.bullets_text.format('bullets="-,+,*"'))
        self.assert_In('- Heading1', toc_txt)
        self.assert_In('+ Heading2', toc_txt)
        self.assert_In('+ Heading2-2', toc_txt)
        self.assert_In('* Heading3', toc_txt)
        self.assert_In('* Heading3-2', toc_txt)
        self.assert_In('- Heading4', toc_txt)
        self.assert_In('- Heading4-2', toc_txt)
        self.assert_In('+ Heading5', toc_txt)
        self.assert_In('* Heading6', toc_txt)
    def test_bullets_4values(self):
        toc_txt = self.commonSetup(self.bullets_text.format('bullets="-,+,-,*"'))
        self.assert_In('- Heading1', toc_txt)
        self.assert_In('+ Heading2', toc_txt)
        self.assert_In('+ Heading2-2', toc_txt)
        self.assert_In('- Heading3', toc_txt)
        self.assert_In('- Heading3-2', toc_txt)
        self.assert_In('* Heading4', toc_txt)
        self.assert_In('* Heading4-2', toc_txt)
        self.assert_In('- Heading5', toc_txt)
        self.assert_In('+ Heading6', toc_txt)<|endoftext|>


<commit_before>"""
Form classes
"""

from django.utils.datastructures import SortedDict, MultiValueDict
from django.utils.html import escape
from fields import Field
from widgets import TextInput, Textarea, HiddenInput
from util import StrAndUnicode, ErrorDict, ErrorList, ValidationError

__all__ = ('BaseForm', 'Form')

NON_FIELD_ERRORS = '__all__'

def pretty_name(name):
    "Converts 'first_name' to 'First name'"
    name = name[0].upper() + name[1:]
    return name.replace('_', ' ')

class SortedDictFromList(SortedDict):
    "A dictionary that keeps its keys in the order in which they're inserted."
    # This is different than django.utils.datastructures.SortedDict, because
    # this takes a list/tuple as the argument to __init__().
    def __init__(self, data=None):
        if data is None: data = []
        self.keyOrder = [d[0] for d in data]
        dict.__init__(self, dict(data))

class DeclarativeFieldsMetaclass(type):
    "Metaclass that converts Field attributes to a dictionary called 'fields'."
    def __new__(cls, name, bases, attrs):
        fields = [(name, attrs.pop(name)) for name, obj in attrs.items() if isinstance(obj, Field)]
        fields.sort(lambda x, y: cmp(x[1].creation_counter, y[1].creation_counter))
        attrs['fields'] = SortedDictFromList(fields)
        return type.__new__(cls, name, bases, attrs)

class BaseForm(StrAndUnicode):
    # This is the main implementation of all the Form logic. Note that this
    # class is different than Form. See the comments by the Form class for more
    # information. Any improvements to the form API should be made to *this*
    # class, not to the Form class.
    def __init__(self, data=None, auto_id='id_%s', prefix=None):
        self.is_bound = data is not None
        self.data = data or {}
        self.auto_id = auto_id
        self.prefix = prefix
        self.__errors = None # Stores the errors after clean() has been called.

    def __unicode__(self):
        return self.as_table()

    def __iter__(self):
        for name, field in self.fields.items():
            yield BoundField(self, field, name)

    def __getitem__(self, name):
        "Returns a BoundField with the given name."
        try:
            field = self.fields[name]
        except KeyError:
            raise KeyError('Key %r not found in Form' % name)
        return BoundField(self, field, name)

    def _errors(self):
        "Returns an ErrorDict for self.data"
        if self.__errors is None:
            self.full_clean()
        return self.__errors
    errors = property(_errors)

    def is_valid(self):
        """
        Returns True if the form has no errors. Otherwise, False. If errors are
        being ignored, returns False.
        """
        return self.is_bound and not bool(self.errors)

    def add_prefix(self, field_name):
        """
        Returns the field name with a prefix appended, if this Form has a
        prefix set.

        Subclasses may wish to override.
        """
        return self.prefix and ('%s-%s' % (self.prefix, field_name)) or field_name

    def _html_output(self, normal_row, error_row, row_ender, errors_on_separate_row):
        "Helper function for outputting HTML. Used by as_table(), as_ul(), as_p()."
        top_errors = self.non_field_errors() # Errors that should be displayed above all fields.
        output, hidden_fields = [], []
        for name, field in self.fields.items():
            bf = BoundField(self, field, name)
            bf_errors = bf.errors # Cache in local variable.
            if bf.is_hidden:
                if bf_errors:
                    top_errors.extend(['(Hidden field %s) %s' % (name, e) for e in bf_errors])
                hidden_fields.append(unicode(bf))
            else:
                if errors_on_separate_row and bf_errors:
                    output.append(error_row % bf_errors)
                label = bf.label and bf.label_tag(escape(bf.label + ':')) or ''
                output.append(normal_row % {'errors': bf_errors, 'label': label, 'field': bf})
        if top_errors:
            output.insert(0, error_row % top_errors)
        if hidden_fields: # Insert any hidden fields in the last row.
            str_hidden = u''.join(hidden_fields)
            if output:
                last_row = output[-1]
                # Chop off the trailing row_ender (e.g. '
') and insert the hidden fields.
                output[-1] = last_row[:-len(row_ender)] + str_hidden + row_ender
            else: # If there aren't any rows in the output, just append the hidden fields.
                output.append(str_hidden)
        return u'\n'.join(output)

    def as_table(self):
        "Returns this form rendered as HTML
s -- excluding the

."
        return self._html_output(u'
%(label)s	%(errors)s%(field)s
', u'
%s
', '
', False)

    def as_ul(self):
        "Returns this form rendered as HTML
s -- excluding the

."
        return self._html_output(u'
%(errors)s%(label)s %(field)s
', u'
%s
', '
', False)

    def as_p(self):
        "Returns this form rendered as HTML
s."
        return self._html_output(u'
%(label)s %(field)s
', u'
%s
', '
', True)

    def non_field_errors(self):
        """
        Returns an ErrorList of errors that aren't associated with a particular
        field -- i.e., from Form.clean(). Returns an empty ErrorList if there
        are none.
        """
        return self.errors.get(NON_FIELD_ERRORS, ErrorList())

    def full_clean(self):
        """
        Cleans all of self.data and populates self.__errors and self.clean_data.
        """
        errors = ErrorDict()
        if not self.is_bound: # Stop further processing.
            self.__errors = errors
            return
        self.clean_data = {}
        for name, field in self.fields.items():
            # value_from_datadict() gets the data from the dictionary.
            # Each widget type knows how to retrieve its own data, because some
            # widgets split data over several HTML fields.
            value = field.widget.value_from_datadict(self.data, self.add_prefix(name))
            try:
                value = field.clean(value)
                self.clean_data[name] = value
                if hasattr(self, 'clean_%s' % name):
                    value = getattr(self, 'clean_%s' % name)()
                self.clean_data[name] = value
            except ValidationError, e:
                errors[name] = e.messages
        try:
            self.clean_data = self.clean()
        except ValidationError, e:
            errors[NON_FIELD_ERRORS] = e.messages
        if errors:
            delattr(self, 'clean_data')
        self.__errors = errors

    def clean(self):
        """
        Hook for doing any extra form-wide cleaning after Field.clean() been
        called on every field. Any ValidationError raised by this method will
        not be associated with a particular field; it will have a special-case
        association with the field named '__all__'.
        """
        return self.clean_data

class Form(BaseForm):
    "A collection of Fields, plus their associated data."
    # This is a separate class from BaseForm in order to abstract the way
    # self.fields is specified. This class (Form) is the one that does the
    # fancy metaclass stuff purely for the semantic sugar -- it allows one
    # to define a form using declarative syntax.
    # BaseForm itself has no way of designating self.fields.
    __metaclass__ = DeclarativeFieldsMetaclass

class BoundField(StrAndUnicode):
    "A Field plus data"
    def __init__(self, form, field, name):
        self.form = form
        self.field = field
        self.name = name
        self.html_name = form.add_prefix(name)
        if self.field.label is None:
            self.label = pretty_name(name)
        else:
            self.label = self.field.label

    def __unicode__(self):
        "Renders this field as an HTML widget."
        # Use the 'widget' attribute on the field to determine which type
        # of HTML widget to use.
        value = self.as_widget(self.field.widget)
        if not isinstance(value, basestring):
            # Some Widget render() methods -- notably RadioSelect -- return a
            # "special" object rather than a string. Call the __str__() on that
            # object to get its rendered value.
            value = value.__str__()
        return value

    def _errors(self):
        """
        Returns an ErrorList for this field. Returns an empty ErrorList
        if there are none.
        """
        return self.form.errors.get(self.name, ErrorList())
    errors = property(_errors)

    def as_widget(self, widget, attrs=None):
        attrs = attrs or {}
        auto_id = self.auto_id
        if auto_id and not attrs.has_key('id') and not widget.attrs.has_key('id'):
            attrs['id'] = auto_id
        if not self.form.is_bound:
            data = self.field.initial
        else:
            data = self.data
        return widget.render(self.html_name, data, attrs=attrs)

    def as_text(self, attrs=None):
        """
        Returns a string of HTML for representing this as an <input type="text">.
        """
        return self.as_widget(TextInput(), attrs)

    def as_textarea(self, attrs=None):
        "Returns a string of HTML for representing this as a <textarea>."
        return self.as_widget(Textarea(), attrs)

    def as_hidden(self, attrs=None):
        """
        Returns a string of HTML for representing this as an <input type="hidden">.
        """
        return self.as_widget(HiddenInput(), attrs)

    def _data(self):
        """
        Returns the data for this BoundField, or None if it wasn't given.
        """
        return self.field.widget.value_from_datadict(self.form.data, self.html_name)
    data = property(_data)

    def label_tag(self, contents=None):
        """
        Wraps the given contents in a , if the field has an ID attribute.
        Does not HTML-escape the contents. If contents aren't given, uses the
        field's HTML-escaped label.
        """
        contents = contents or escape(self.label)
        widget = self.field.widget
        id_ = widget.attrs.get('id') or self.auto_id
        if id_:
            contents = '%s' % (widget.id_for_label(id_), contents)
        return contents

    def _is_hidden(self):
        "Returns True if this BoundField's widget is hidden."
        return self.field.widget.is_hidden
    is_hidden = property(_is_hidden)

    def _auto_id(self):
        """
        Calculates and returns the ID attribute for this BoundField, if the
        associated Form has specified auto_id. Returns an empty string otherwise.
        """
        auto_id = self.form.auto_id
        if auto_id and '%s' in str(auto_id):
            return str(auto_id) % self.html_name
        elif auto_id:
            return self.html_name
        return ''
    auto_id = property(_auto_id)
<commit_msg>newforms: Fixed Unicode issue on Python 2.3 when a BoundField's __unicode__() included non-ASCII characters. Thanks for reporting the error, Johannes Froehlich<commit_after>"""
Form classes
"""

from django.utils.datastructures import SortedDict, MultiValueDict
from django.utils.html import escape
from fields import Field
from widgets import TextInput, Textarea, HiddenInput
from util import StrAndUnicode, ErrorDict, ErrorList, ValidationError

__all__ = ('BaseForm', 'Form')

NON_FIELD_ERRORS = '__all__'

def pretty_name(name):
    "Converts 'first_name' to 'First name'"
    name = name[0].upper() + name[1:]
    return name.replace('_', ' ')

class SortedDictFromList(SortedDict):
    "A dictionary that keeps its keys in the order in which they're inserted."
    # This is different than django.utils.datastructures.SortedDict, because
    # this takes a list/tuple as the argument to __init__().
    def __init__(self, data=None):
        if data is None: data = []
        self.keyOrder = [d[0] for d in data]
        dict.__init__(self, dict(data))

class DeclarativeFieldsMetaclass(type):
    "Metaclass that converts Field attributes to a dictionary called 'fields'."
    def __new__(cls, name, bases, attrs):
        fields = [(name, attrs.pop(name)) for name, obj in attrs.items() if isinstance(obj, Field)]
        fields.sort(lambda x, y: cmp(x[1].creation_counter, y[1].creation_counter))
        attrs['fields'] = SortedDictFromList(fields)
        return type.__new__(cls, name, bases, attrs)

class BaseForm(StrAndUnicode):
    # This is the main implementation of all the Form logic. Note that this
    # class is different than Form. See the comments by the Form class for more
    # information. Any improvements to the form API should be made to *this*
    # class, not to the Form class.
    def __init__(self, data=None, auto_id='id_%s', prefix=None):
        self.is_bound = data is not None
        self.data = data or {}
        self.auto_id = auto_id
        self.prefix = prefix
        self.__errors = None # Stores the errors after clean() has been called.

    def __unicode__(self):
        return self.as_table()

    def __iter__(self):
        for name, field in self.fields.items():
            yield BoundField(self, field, name)

    def __getitem__(self, name):
        "Returns a BoundField with the given name."
        try:
            field = self.fields[name]
        except KeyError:
            raise KeyError('Key %r not found in Form' % name)
        return BoundField(self, field, name)

    def _errors(self):
        "Returns an ErrorDict for self.data"
        if self.__errors is None:
            self.full_clean()
        return self.__errors
    errors = property(_errors)

    def is_valid(self):
        """
        Returns True if the form has no errors. Otherwise, False. If errors are
        being ignored, returns False.
        """
        return self.is_bound and not bool(self.errors)

    def add_prefix(self, field_name):
        """
        Returns the field name with a prefix appended, if this Form has a
        prefix set.

        Subclasses may wish to override.
        """
        return self.prefix and ('%s-%s' % (self.prefix, field_name)) or field_name

    def _html_output(self, normal_row, error_row, row_ender, errors_on_separate_row):
        "Helper function for outputting HTML. Used by as_table(), as_ul(), as_p()."
        top_errors = self.non_field_errors() # Errors that should be displayed above all fields.
        output, hidden_fields = [], []
        for name, field in self.fields.items():
            bf = BoundField(self, field, name)
            bf_errors = bf.errors # Cache in local variable.
            if bf.is_hidden:
                if bf_errors:
                    top_errors.extend(['(Hidden field %s) %s' % (name, e) for e in bf_errors])
                hidden_fields.append(unicode(bf))
            else:
                if errors_on_separate_row and bf_errors:
                    output.append(error_row % bf_errors)
                label = bf.label and bf.label_tag(escape(bf.label + ':')) or ''
                output.append(normal_row % {'errors': bf_errors, 'label': label, 'field': unicode(bf)})
        if top_errors:
            output.insert(0, error_row % top_errors)
        if hidden_fields: # Insert any hidden fields in the last row.
            str_hidden = u''.join(hidden_fields)
            if output:
                last_row = output[-1]
                # Chop off the trailing row_ender (e.g. '
') and insert the hidden fields.
                output[-1] = last_row[:-len(row_ender)] + str_hidden + row_ender
            else: # If there aren't any rows in the output, just append the hidden fields.
                output.append(str_hidden)
        return u'\n'.join(output)

    def as_table(self):
        "Returns this form rendered as HTML
s -- excluding the

."
        return self._html_output(u'
%(label)s	%(errors)s%(field)s
', u'
%s
', '
', False)

    def as_ul(self):
        "Returns this form rendered as HTML
s -- excluding the

."
        return self._html_output(u'
%(errors)s%(label)s %(field)s
', u'
%s
', '
', False)

    def as_p(self):
        "Returns this form rendered as HTML
s."
        return self._html_output(u'
%(label)s %(field)s
', u'
%s
', '
', True)

    def non_field_errors(self):
        """
        Returns an ErrorList of errors that aren't associated with a particular
        field -- i.e., from Form.clean(). Returns an empty ErrorList if there
        are none.
        """
        return self.errors.get(NON_FIELD_ERRORS, ErrorList())

    def full_clean(self):
        """
        Cleans all of self.data and populates self.__errors and self.clean_data.
        """
        errors = ErrorDict()
        if not self.is_bound: # Stop further processing.
            self.__errors = errors
            return
        self.clean_data = {}
        for name, field in self.fields.items():
            # value_from_datadict() gets the data from the dictionary.
            # Each widget type knows how to retrieve its own data, because some
            # widgets split data over several HTML fields.
            value = field.widget.value_from_datadict(self.data, self.add_prefix(name))
            try:
                value = field.clean(value)
                self.clean_data[name] = value
                if hasattr(self, 'clean_%s' % name):
                    value = getattr(self, 'clean_%s' % name)()
                self.clean_data[name] = value
            except ValidationError, e:
                errors[name] = e.messages
        try:
            self.clean_data = self.clean()
        except ValidationError, e:
            errors[NON_FIELD_ERRORS] = e.messages
        if errors:
            delattr(self, 'clean_data')
        self.__errors = errors

    def clean(self):
        """
        Hook for doing any extra form-wide cleaning after Field.clean() been
        called on every field. Any ValidationError raised by this method will
        not be associated with a particular field; it will have a special-case
        association with the field named '__all__'.
        """
        return self.clean_data

class Form(BaseForm):
    "A collection of Fields, plus their associated data."
    # This is a separate class from BaseForm in order to abstract the way
    # self.fields is specified. This class (Form) is the one that does the
    # fancy metaclass stuff purely for the semantic sugar -- it allows one
    # to define a form using declarative syntax.
    # BaseForm itself has no way of designating self.fields.
    __metaclass__ = DeclarativeFieldsMetaclass

class BoundField(StrAndUnicode):
    "A Field plus data"
    def __init__(self, form, field, name):
        self.form = form
        self.field = field
        self.name = name
        self.html_name = form.add_prefix(name)
        if self.field.label is None:
            self.label = pretty_name(name)
        else:
            self.label = self.field.label

    def __unicode__(self):
        "Renders this field as an HTML widget."
        # Use the 'widget' attribute on the field to determine which type
        # of HTML widget to use.
        value = self.as_widget(self.field.widget)
        if not isinstance(value, basestring):
            # Some Widget render() methods -- notably RadioSelect -- return a
            # "special" object rather than a string. Call the __str__() on that
            # object to get its rendered value.
            value = value.__str__()
        return value

    def _errors(self):
        """
        Returns an ErrorList for this field. Returns an empty ErrorList
        if there are none.
        """
        return self.form.errors.get(self.name, ErrorList())
    errors = property(_errors)

    def as_widget(self, widget, attrs=None):
        attrs = attrs or {}
        auto_id = self.auto_id
        if auto_id and not attrs.has_key('id') and not widget.attrs.has_key('id'):
            attrs['id'] = auto_id
        if not self.form.is_bound:
            data = self.field.initial
        else:
            data = self.data
        return widget.render(self.html_name, data, attrs=attrs)

    def as_text(self, attrs=None):
        """
        Returns a string of HTML for representing this as an <input type="text">.
        """
        return self.as_widget(TextInput(), attrs)

    def as_textarea(self, attrs=None):
        "Returns a string of HTML for representing this as a <textarea>."
        return self.as_widget(Textarea(), attrs)

    def as_hidden(self, attrs=None):
        """
        Returns a string of HTML for representing this as an <input type="hidden">.
        """
        return self.as_widget(HiddenInput(), attrs)

    def _data(self):
        """
        Returns the data for this BoundField, or None if it wasn't given.
        """
        return self.field.widget.value_from_datadict(self.form.data, self.html_name)
    data = property(_data)

    def label_tag(self, contents=None):
        """
        Wraps the given contents in a , if the field has an ID attribute.
        Does not HTML-escape the contents. If contents aren't given, uses the
        field's HTML-escaped label.
        """
        contents = contents or escape(self.label)
        widget = self.field.widget
        id_ = widget.attrs.get('id') or self.auto_id
        if id_:
            contents = '%s' % (widget.id_for_label(id_), contents)
        return contents

    def _is_hidden(self):
        "Returns True if this BoundField's widget is hidden."
        return self.field.widget.is_hidden
    is_hidden = property(_is_hidden)

    def _auto_id(self):
        """
        Calculates and returns the ID attribute for this BoundField, if the
        associated Form has specified auto_id. Returns an empty string otherwise.
        """
        auto_id = self.form.auto_id
        if auto_id and '%s' in str(auto_id):
            return str(auto_id) % self.html_name
        elif auto_id:
            return self.html_name
        return ''
    auto_id = property(_auto_id)
<|endoftext|>


<commit_before>from __future__ import unicode_literals
from frappe import _

def get_data():
	return [
		{
			"label": _("Bill of Materials"),
			"items": [
				{
					"type": "doctype",
					"name": "Item",
					"description": _("All Products or Services."),
					"onboard": 1,
				},
				{
					"type": "doctype",
					"name": "BOM",
					"description": _("Bill of Materials (BOM)"),
					"label": _("Bill of Materials"),
					"onboard": 1,
					"dependencies": ["Item"]
				},
				{
					"type": "doctype",
					"name": "BOM Browser",
					"icon": "fa fa-sitemap",
					"label": _("BOM Browser"),
					"description": _("Tree of Bill of Materials"),
					"link": "Tree/BOM",
					"onboard": 1,
					"dependencies": ["Item"]
				},

				{
					"type": "doctype",
					"name": "Workstation",
					"description": _("Where manufacturing operations are carried."),
				},
				{
					"type": "doctype",
					"name": "Operation",
					"description": _("Details of the operations carried out."),
				},
				{
					"type": "doctype",
					"name": "Routing"
				}

			]
		},
		{
			"label": _("Production"),
			"icon": "fa fa-star",
			"items": [
				{
					"type": "doctype",
					"name": "Work Order",
					"description": _("Orders released for production."),
					"onboard": 1,
					"dependencies": ["Item", "BOM"]
				},
				{
					"type": "doctype",
					"name": "Production Plan",
					"description": _("Generate Material Requests (MRP) and Work Orders."),
					"onboard": 1,
					"dependencies": ["Item", "BOM"]
				},
				{
					"type": "doctype",
					"name": "Stock Entry",
					"onboard": 1,
					"dependencies": ["Item"]
				},
				{
					"type": "doctype",
					"name": "Timesheet",
					"description": _("Time Sheet for manufacturing."),
					"onboard": 1,
					"dependencies": ["Activity Type"]
				},
				{
					"type": "doctype",
					"name": "Job Card"
				}
			]
		},
		{
			"label": _("Tools"),
			"icon": "fa fa-wrench",
			"items": [
				{
					"type": "doctype",
					"name": "BOM Update Tool",
					"description": _("Replace BOM and update latest price in all BOMs"),
				},
			]
		},
		{
			"label": _("Settings"),
			"items": [
				{
					"type": "doctype",
					"name": "Manufacturing Settings",
					"description": _("Global settings for all manufacturing processes."),
				}
			]
		},
		{
			"label": _("Reports"),
			"icon": "fa fa-list",
			"items": [
				{
					"type": "report",
					"is_query_report": True,
					"name": "Open Work Orders",
					"doctype": "Work Order"
				},
				{
					"type": "report",
					"is_query_report": True,
					"name": "Work Orders in Progress",
					"doctype": "Work Order"
				},
				{
					"type": "report",
					"is_query_report": True,
					"name": "Issued Items Against Work Order",
					"doctype": "Work Order"
				},
				{
					"type": "report",
					"is_query_report": True,
					"name": "Completed Work Orders",
					"doctype": "Work Order"
				},
				{
					"type": "report",
					"is_query_report": True,
					"name": "Production Analytics",
					"doctype": "Work Order"
				},
				{
					"type": "report",
					"is_query_report": True,
					"name": "BOM Search",
					"doctype": "BOM"
				},
				{
					"type": "report",
					"is_query_report": True,
					"name": "BOM Stock Report",
					"doctype": "BOM"
				}
			]
		},
		{
			"label": _("Help"),
			"icon": "fa fa-facetime-video",
			"items": [
				{
					"type": "help",
					"label": _("Bill of Materials"),
					"youtube_id": "hDV0c1OeWLo"
				},
				{
					"type": "help",
					"label": _("Work Order"),
					"youtube_id": "ZotgLyp2YFY"
				},
			]
		}
	]
<commit_msg>fix: Add BOM Comparison Tool to module view<commit_after>from __future__ import unicode_literals
from frappe import _

def get_data():
	return [
		{
			"label": _("Bill of Materials"),
			"items": [
				{
					"type": "doctype",
					"name": "Item",
					"description": _("All Products or Services."),
					"onboard": 1,
				},
				{
					"type": "doctype",
					"name": "BOM",
					"description": _("Bill of Materials (BOM)"),
					"label": _("Bill of Materials"),
					"onboard": 1,
					"dependencies": ["Item"]
				},
				{
					"type": "doctype",
					"name": "BOM Browser",
					"icon": "fa fa-sitemap",
					"label": _("BOM Browser"),
					"description": _("Tree of Bill of Materials"),
					"link": "Tree/BOM",
					"onboard": 1,
					"dependencies": ["Item"]
				},

				{
					"type": "doctype",
					"name": "Workstation",
					"description": _("Where manufacturing operations are carried."),
				},
				{
					"type": "doctype",
					"name": "Operation",
					"description": _("Details of the operations carried out."),
				},
				{
					"type": "doctype",
					"name": "Routing"
				}

			]
		},
		{
			"label": _("Production"),
			"icon": "fa fa-star",
			"items": [
				{
					"type": "doctype",
					"name": "Work Order",
					"description": _("Orders released for production."),
					"onboard": 1,
					"dependencies": ["Item", "BOM"]
				},
				{
					"type": "doctype",
					"name": "Production Plan",
					"description": _("Generate Material Requests (MRP) and Work Orders."),
					"onboard": 1,
					"dependencies": ["Item", "BOM"]
				},
				{
					"type": "doctype",
					"name": "Stock Entry",
					"onboard": 1,
					"dependencies": ["Item"]
				},
				{
					"type": "doctype",
					"name": "Timesheet",
					"description": _("Time Sheet for manufacturing."),
					"onboard": 1,
					"dependencies": ["Activity Type"]
				},
				{
					"type": "doctype",
					"name": "Job Card"
				}
			]
		},
		{
			"label": _("Tools"),
			"icon": "fa fa-wrench",
			"items": [
				{
					"type": "doctype",
					"name": "BOM Update Tool",
					"description": _("Replace BOM and update latest price in all BOMs"),
				},
				{
					"type": "page",
					"label": _("BOM Comparison Tool"),
					"name": "bom-comparison-tool",
					"description": _("Compare BOMs for changes in Raw Materials and Operations"),
					"data_doctype": "BOM"
				},
			]
		},
		{
			"label": _("Settings"),
			"items": [
				{
					"type": "doctype",
					"name": "Manufacturing Settings",
					"description": _("Global settings for all manufacturing processes."),
				}
			]
		},
		{
			"label": _("Reports"),
			"icon": "fa fa-list",
			"items": [
				{
					"type": "report",
					"is_query_report": True,
					"name": "Open Work Orders",
					"doctype": "Work Order"
				},
				{
					"type": "report",
					"is_query_report": True,
					"name": "Work Orders in Progress",
					"doctype": "Work Order"
				},
				{
					"type": "report",
					"is_query_report": True,
					"name": "Issued Items Against Work Order",
					"doctype": "Work Order"
				},
				{
					"type": "report",
					"is_query_report": True,
					"name": "Completed Work Orders",
					"doctype": "Work Order"
				},
				{
					"type": "report",
					"is_query_report": True,
					"name": "Production Analytics",
					"doctype": "Work Order"
				},
				{
					"type": "report",
					"is_query_report": True,
					"name": "BOM Search",
					"doctype": "BOM"
				},
				{
					"type": "report",
					"is_query_report": True,
					"name": "BOM Stock Report",
					"doctype": "BOM"
				}
			]
		},
		{
			"label": _("Help"),
			"icon": "fa fa-facetime-video",
			"items": [
				{
					"type": "help",
					"label": _("Bill of Materials"),
					"youtube_id": "hDV0c1OeWLo"
				},
				{
					"type": "help",
					"label": _("Work Order"),
					"youtube_id": "ZotgLyp2YFY"
				},
			]
		}
	]
<|endoftext|>


<commit_before>import pprint
import logging

from six.moves import urllib

from django.http.request import QueryDict
from django.utils.module_loading import import_string

from .utils import Backend
from .app_settings import app_settings

logger = logging.getLogger(__name__)

class UrllibBackend(Backend):
    def send(self, url, message_data, **kwargs):
        qs = QueryDict(mutable=True)
        qs.update(message_data)

        r = urllib.request.urlopen(urllib.request.Request(
            url,
            qs.urlencode().encode('utf-8'),
        ))

        result = r.read().decode('utf-8')

        return self.validate(r.headers['content-type'], result, message_data)

class RequestsBackend(Backend):
    def __init__(self):
        # Lazily import to avoid dependency
        import requests

        self.session = requests.Session()

    def send(self, url, message_data, **kwargs):
        r = self.session.post(url, data=message_data)

        return self.validate(r.headers['Content-Type'], r.text, message_data)

class ConsoleBackend(Backend):
    def send(self, url, message_data, **kwargs):
        print("I: Slack message:")
        pprint.pprint(message_data, indent=4)
        print("-" * 79)

class LoggerBackend(Backend):
    def send(self, url, message_data, **kwargs):
        logger.info(pprint.pformat(message_data, indent=4))

class DisabledBackend(Backend):
    def send(self, url, message_data, **kwargs):
        pass

class CeleryBackend(Backend):
    def __init__(self):
        # Lazily import to avoid dependency
        from .tasks import send
        self._send = send

        # Check we can import our specified backend up-front
        import_string(app_settings.BACKEND_FOR_QUEUE)()

    def send(self, *args, **kwargs):
        # Send asynchronously via Celery
        self._send.delay(*args, **kwargs)

class TestBackend(Backend):
    """
    This backend is for testing.

    Before a test, call `reset_messages`, and after a test, call
    `retrieve_messages` for a list of all messages that have been sent during
    the test.
    """

    def __init__(self, *args, **kwargs):
        super(TestBackend, self).__init__(*args, **kwargs)
        self.reset_messages()

    def send(self, url, message_data, **kwargs):
        self.messages.append(message_data)

    def reset_messages(self):
        self.messages = []

    def retrieve_messages(self):
        messages = self.messages
        self.reset_messages()
        return messages

# For backwards-compatibility
Urllib2Backend = UrllibBackend
<commit_msg>Add backend for asynchronous sending with Django-Q<commit_after>import pprint
import logging

from six.moves import urllib

from django.http.request import QueryDict
from django.utils.module_loading import import_string

from .utils import Backend
from .app_settings import app_settings

logger = logging.getLogger(__name__)

class UrllibBackend(Backend):
    def send(self, url, message_data, **kwargs):
        qs = QueryDict(mutable=True)
        qs.update(message_data)

        r = urllib.request.urlopen(urllib.request.Request(
            url,
            qs.urlencode().encode('utf-8'),
        ))

        result = r.read().decode('utf-8')

        return self.validate(r.headers['content-type'], result, message_data)

class RequestsBackend(Backend):
    def __init__(self):
        # Lazily import to avoid dependency
        import requests

        self.session = requests.Session()

    def send(self, url, message_data, **kwargs):
        r = self.session.post(url, data=message_data)

        return self.validate(r.headers['Content-Type'], r.text, message_data)

class ConsoleBackend(Backend):
    def send(self, url, message_data, **kwargs):
        print("I: Slack message:")
        pprint.pprint(message_data, indent=4)
        print("-" * 79)

class LoggerBackend(Backend):
    def send(self, url, message_data, **kwargs):
        logger.info(pprint.pformat(message_data, indent=4))

class DisabledBackend(Backend):
    def send(self, url, message_data, **kwargs):
        pass

class CeleryBackend(Backend):
    def __init__(self):
        # Lazily import to avoid dependency
        from .tasks import send
        self._send = send

        # Check we can import our specified backend up-front
        import_string(app_settings.BACKEND_FOR_QUEUE)()

    def send(self, *args, **kwargs):
        # Send asynchronously via Celery
        self._send.delay(*args, **kwargs)

class DjangoQBackend(Backend):
    def __init__(self):
        # Check we can import our specified backend up-front
        import_string(app_settings.BACKEND_FOR_QUEUE)()

    @staticmethod
    def _send(*args, **kwargs):
        backend = import_string(app_settings.BACKEND_FOR_QUEUE)()
        return backend.send(*args, **kwargs)

    def send(self, *args, **kwargs):
        # Send asynchronously via Django-Q
        from django_q.tasks import async_task
        async_task(self._send, *args, group='django-slack', q_options=kwargs)

class TestBackend(Backend):
    """
    This backend is for testing.

    Before a test, call `reset_messages`, and after a test, call
    `retrieve_messages` for a list of all messages that have been sent during
    the test.
    """

    def __init__(self, *args, **kwargs):
        super(TestBackend, self).__init__(*args, **kwargs)
        self.reset_messages()

    def send(self, url, message_data, **kwargs):
        self.messages.append(message_data)

    def reset_messages(self):
        self.messages = []

    def retrieve_messages(self):
        messages = self.messages
        self.reset_messages()
        return messages

# For backwards-compatibility
Urllib2Backend = UrllibBackend
<|endoftext|>