<commit_before># -*- coding: utf-8 -*-
# vim: tabstop=4 shiftwidth=4 softtabstop=4
#
# Copyright (C) 2010-2018 GEM Foundation
#
# OpenQuake is free software: you can redistribute it and/or modify it
# under the terms of the GNU Affero General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# OpenQuake is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with OpenQuake. If not, see <http://www.gnu.org/licenses/>.
import re
import logging
import operator
import collections
import numpy
from openquake.hazardlib import probability_map, stats

MAX_INT = 2 ** 31 - 1
U16 = numpy.uint16
U32 = numpy.uint32
F32 = numpy.float32
weight = operator.attrgetter('weight')
rlz_dt = numpy.dtype([
    ('branch_path', 'S200'), ('gsims', 'S100'), ('weight', F32)])

class LtRealization(object):
    """
    Composite realization build on top of a source model realization and
    a GSIM realization.
    """
    def __init__(self, ordinal, sm_lt_path, gsim_rlz, weight):
        self.ordinal = ordinal
        self.sm_lt_path = tuple(sm_lt_path)
        self.gsim_rlz = gsim_rlz
        self.weight = weight

    def __repr__(self):
        return '<%d,%s,w=%s>' % (self.ordinal, self.uid, self.weight)

    @property
    def gsim_lt_path(self):
        return self.gsim_rlz.lt_path

    @property
    def uid(self):
        """An unique identifier for effective realizations"""
        return '_'.join(self.sm_lt_path) + '~' + self.gsim_rlz.uid

    def __lt__(self, other):
        return self.ordinal < other.ordinal

    def __eq__(self, other):
        return repr(self) == repr(other)

    def __ne__(self, other):
        return repr(self) != repr(other)

    def __hash__(self):
        return hash(repr(self))

class RlzsAssoc(object):
    """
    Realization association class. It should not be instantiated directly,
    but only via the method :meth:
    `openquake.commonlib.source.CompositeSourceModel.get_rlzs_assoc`.

    :attr realizations: list of :class:`LtRealization` objects
    :attr gsim_by_trt: list of dictionaries {trt: gsim}
    :attr rlzs_assoc: dictionary {src_group_id, gsim: rlzs}
    :attr rlzs_by_smodel: list of lists of realizations

    For instance, for the non-trivial logic tree in
    :mod:`openquake.qa_tests_data.classical.case_15`, which has 4 tectonic
    region types and 4 + 2 + 2 realizations, there are the following
    associations:

    (0, 'BooreAtkinson2008()') ['#0-SM1-BA2008_C2003', '#1-SM1-BA2008_T2002']
    (0, 'CampbellBozorgnia2008()') ['#2-SM1-CB2008_C2003', '#3-SM1-CB2008_T2002']
    (1, 'Campbell2003()') ['#0-SM1-BA2008_C2003', '#2-SM1-CB2008_C2003']
    (1, 'ToroEtAl2002()') ['#1-SM1-BA2008_T2002', '#3-SM1-CB2008_T2002']
    (2, 'BooreAtkinson2008()') ['#4-SM2_a3pt2b0pt8-BA2008']
    (2, 'CampbellBozorgnia2008()') ['#5-SM2_a3pt2b0pt8-CB2008']
    (3, 'BooreAtkinson2008()') ['#6-SM2_a3b1-BA2008']
    (3, 'CampbellBozorgnia2008()') ['#7-SM2_a3b1-CB2008']
    """
    def __init__(self, csm_info):
        self.seed = csm_info.seed
        self.csm_info = csm_info
        self.num_samples = csm_info.num_samples
        self.gsim_by_trt = []  # rlz.ordinal -> {trt: gsim}
        self.rlzs_by_smodel = {sm.ordinal: [] for sm in csm_info.source_models}

    def get_rlzs_by_gsim(self, trt_or_grp_id, sm_id=None):
        """
        :param trt_or_grp_id: a tectonic region type or a source group ID
        :param sm_id: source model ordinal (or None)
        :returns: a dictionary gsim -> rlzs
        """
        if isinstance(trt_or_grp_id, (int, U32)):  # grp_id
            trt = self.csm_info.trt_by_grp[trt_or_grp_id]
            sm_id = self.csm_info.get_sm_by_grp()[trt_or_grp_id]
        else:  # assume TRT string
            trt = trt_or_grp_id
        acc = collections.defaultdict(list)
        if sm_id is None:  # full dictionary
            for rlz, gsim_by_trt in zip(self.realizations, self.gsim_by_trt):
                acc[gsim_by_trt[trt]].append(rlz.ordinal)
        else:  # dictionary for the selected source model
            for rlz in self.rlzs_by_smodel[sm_id]:
                gsim_by_trt = self.gsim_by_trt[rlz.ordinal]
                try:  # if there is a single TRT
                    [gsim] = gsim_by_trt.values()
                except ValueError:  # there is more than 1 TRT
                    gsim = gsim_by_trt[trt]
                acc[gsim].append(rlz.ordinal)
        return {gsim: numpy.array(acc[gsim], dtype=U16)
                for gsim in sorted(acc)}

    def by_grp(self):
        """
        :returns: a dictionary grp -> rlzis
        """
        dic = {}  # grp -> [(gsim_idx, rlzis), ...]
        for sm in self.csm_info.source_models:
            for sg in sm.src_groups:
                if not sg.eff_ruptures:
                    continue
                rlzs_by_gsim = self.get_rlzs_by_gsim(sg.trt, sm.ordinal)
                if not rlzs_by_gsim:
                    continue
                dic['grp-%02d' % sg.id] = numpy.array(
                    list(rlzs_by_gsim.values()))
        return dic

    def _init(self):
        """
        Finalize the initialization of the RlzsAssoc object by setting
        the (reduced) weights of the realizations.
        """
        if self.num_samples:
            assert len(self.realizations) == self.num_samples, (
                len(self.realizations), self.num_samples)
            tot_weight = sum(rlz.weight for rlz in self.realizations)
            for rlz in self.realizations:
                rlz.weight /= tot_weight
        else:
            tot_weight = sum(rlz.weight for rlz in self.realizations)
            if tot_weight == 0:
                raise ValueError('All realizations have zero weight??')
            elif abs(tot_weight - 1) > 1E-8:
                # this may happen for rounding errors or because of the
                # logic tree reduction; we ensure the sum of the weights is 1
                for rlz in self.realizations:
                    rlz.weight = rlz.weight / tot_weight

    @property
    def realizations(self):
        """Flat list with all the realizations"""
        return sum(self.rlzs_by_smodel.values(), [])

    @property
    def weights(self):
        """Array with the weight of the realizations"""
        return numpy.array([rlz.weight for rlz in self.realizations])

    def combine_pmaps(self, pmap_by_grp):
        """
        :param pmap_by_grp: dictionary group string -> probability map
        :returns: a list of probability maps, one per realization
        """
        grp = list(pmap_by_grp)[0]  # pmap_by_grp must be non-empty
        num_levels = pmap_by_grp[grp].shape_y
        pmaps = [probability_map.ProbabilityMap(num_levels, 1)
                 for _ in self.realizations]
        array = self.by_grp()
        for grp in pmap_by_grp:
            for gsim_idx, rlzis in enumerate(array[grp]):
                pmap = pmap_by_grp[grp].extract(gsim_idx)
                for rlzi in rlzis:
                    pmaps[rlzi] |= pmap
        return pmaps

    def compute_pmap_stats(self, pmap_by_grp, statfuncs):
        """
        :param pmap_by_grp: dictionary group string -> probability map
        :param statfuncs: a list of statistical functions
        :returns: a probability map containing all statistics
        """
        pmaps = self.combine_pmaps(pmap_by_grp)
        return stats.compute_pmap_stats(pmaps, statfuncs, self.weights)

    def get_rlz(self, rlzstr):
        """
        Get a Realization instance for a string of the form 'rlz-\d+'
        """
        mo = re.match('rlz-(\d+)', rlzstr)
        if not mo:
            return
        return self.realizations[int(mo.group(1))]

    def _add_realizations(self, offset, lt_model, all_trts, gsim_rlzs):
        idx = numpy.arange(offset, offset + len(gsim_rlzs))
        rlzs = []
        for i, gsim_rlz in enumerate(gsim_rlzs):
            weight = float(lt_model.weight) * float(gsim_rlz.weight)
            rlz = LtRealization(idx[i], lt_model.path, gsim_rlz, weight)
            self.gsim_by_trt.append(dict(zip(all_trts, gsim_rlz.value)))
            rlzs.append(rlz)
        self.rlzs_by_smodel[lt_model.ordinal] = rlzs

    def __len__(self):
        array = self.by_grp()  # TODO: remove this
        return sum(len(array[grp]) for grp in array)

    def __repr__(self):
        pairs = []
        dic = self.by_grp()
        for grp in sorted(dic):
            grp_id = int(grp[4:])
            gsims = self.csm_info.get_gsims(grp_id)
            for gsim_idx, rlzis in dic[grp]:
                if len(rlzis) > 10:  # short representation
                    rlzis = ['%d realizations' % len(rlzis)]
                pairs.append(('%s,%s' % (grp_id, gsims[gsim_idx]), rlzis))
        return '<%s(size=%d, rlzs=%d)\n%s>' % (
            self.__class__.__name__, len(self), len(self.realizations),
            '\n'.join('%s: %s' % pair for pair in pairs))

def accept_path(path, ref_path):
    """
    :param path: a logic tree path (list or tuple of strings)
    :param ref_path: reference logic tree path
    :returns: True if `path` is consistent with `ref_path`, False otherwise

    >>> accept_path(['SM2'], ('SM2', 'a3b1'))
    False
    >>> accept_path(['SM2', '@'], ('SM2', 'a3b1'))
    True
    >>> accept_path(['@', 'a3b1'], ('SM2', 'a3b1'))
    True
    >>> accept_path('@@', ('SM2', 'a3b1'))
    True
    """
    if len(path) != len(ref_path):
        return False
    for a, b in zip(path, ref_path):
        if a != '@' and a != b:
            return False
    return True

def get_rlzs_assoc(cinfo, sm_lt_path=None, trts=None):
    """
    :param cinfo: a :class:`openquake.commonlib.source.CompositionInfo`
    :param sm_lt_path: logic tree path tuple used to select a source model
    :param trts: tectonic region types to accept
    """
    assoc = RlzsAssoc(cinfo)
    offset = 0
    trtset = set(cinfo.gsim_lt.tectonic_region_types)
    for smodel in cinfo.source_models:
        # discard source models with non-acceptable lt_path
        if sm_lt_path and not accept_path(smodel.path, sm_lt_path):
            continue

        # collect the effective tectonic region types and ruptures
        trts_ = set()
        for sg in smodel.src_groups:
            if sg.eff_ruptures:
                if (trts and sg.trt in trts) or not trts:
                    trts_.add(sg.trt)

        # recompute the GSIM logic tree if needed
        if trtset != trts_:
            before = cinfo.gsim_lt.get_num_paths()
            gsim_lt = cinfo.gsim_lt.reduce(trts_)
            after = gsim_lt.get_num_paths()
            if sm_lt_path and before > after:
                # print the warning only when saving the logic tree,
                # i.e. when called with sm_lt_path in store_csm_info
                logging.warn('Reducing the logic tree of %s from %d to %d '
                             'realizations', smodel.name, before, after)
            gsim_rlzs = list(gsim_lt)
            all_trts = gsim_lt.all_trts
        else:
            gsim_rlzs = cinfo.gsim_rlzs
            all_trts = cinfo.gsim_lt.all_trts

        rlzs = cinfo._get_rlzs(smodel, gsim_rlzs, cinfo.seed + offset)
        assoc._add_realizations(offset, smodel, all_trts, rlzs)
        offset += len(rlzs)

    if assoc.realizations:
        assoc._init()
    return assoc
<commit_msg>Fixed RlzsAssoc.__repr__ [skip hazardlib]<commit_after># -*- coding: utf-8 -*-
# vim: tabstop=4 shiftwidth=4 softtabstop=4
#
# Copyright (C) 2010-2018 GEM Foundation
#
# OpenQuake is free software: you can redistribute it and/or modify it
# under the terms of the GNU Affero General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# OpenQuake is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with OpenQuake. If not, see <http://www.gnu.org/licenses/>.
import re
import logging
import operator
import collections
import numpy
from openquake.hazardlib import probability_map, stats

MAX_INT = 2 ** 31 - 1
U16 = numpy.uint16
U32 = numpy.uint32
F32 = numpy.float32
weight = operator.attrgetter('weight')
rlz_dt = numpy.dtype([
    ('branch_path', 'S200'), ('gsims', 'S100'), ('weight', F32)])

class LtRealization(object):
    """
    Composite realization build on top of a source model realization and
    a GSIM realization.
    """
    def __init__(self, ordinal, sm_lt_path, gsim_rlz, weight):
        self.ordinal = ordinal
        self.sm_lt_path = tuple(sm_lt_path)
        self.gsim_rlz = gsim_rlz
        self.weight = weight

    def __repr__(self):
        return '<%d,%s,w=%s>' % (self.ordinal, self.uid, self.weight)

    @property
    def gsim_lt_path(self):
        return self.gsim_rlz.lt_path

    @property
    def uid(self):
        """An unique identifier for effective realizations"""
        return '_'.join(self.sm_lt_path) + '~' + self.gsim_rlz.uid

    def __lt__(self, other):
        return self.ordinal < other.ordinal

    def __eq__(self, other):
        return repr(self) == repr(other)

    def __ne__(self, other):
        return repr(self) != repr(other)

    def __hash__(self):
        return hash(repr(self))

class RlzsAssoc(object):
    """
    Realization association class. It should not be instantiated directly,
    but only via the method :meth:
    `openquake.commonlib.source.CompositeSourceModel.get_rlzs_assoc`.

    :attr realizations: list of :class:`LtRealization` objects
    :attr gsim_by_trt: list of dictionaries {trt: gsim}
    :attr rlzs_assoc: dictionary {src_group_id, gsim: rlzs}
    :attr rlzs_by_smodel: list of lists of realizations

    For instance, for the non-trivial logic tree in
    :mod:`openquake.qa_tests_data.classical.case_15`, which has 4 tectonic
    region types and 4 + 2 + 2 realizations, there are the following
    associations:

    (0, 'BooreAtkinson2008()') ['#0-SM1-BA2008_C2003', '#1-SM1-BA2008_T2002']
    (0, 'CampbellBozorgnia2008()') ['#2-SM1-CB2008_C2003', '#3-SM1-CB2008_T2002']
    (1, 'Campbell2003()') ['#0-SM1-BA2008_C2003', '#2-SM1-CB2008_C2003']
    (1, 'ToroEtAl2002()') ['#1-SM1-BA2008_T2002', '#3-SM1-CB2008_T2002']
    (2, 'BooreAtkinson2008()') ['#4-SM2_a3pt2b0pt8-BA2008']
    (2, 'CampbellBozorgnia2008()') ['#5-SM2_a3pt2b0pt8-CB2008']
    (3, 'BooreAtkinson2008()') ['#6-SM2_a3b1-BA2008']
    (3, 'CampbellBozorgnia2008()') ['#7-SM2_a3b1-CB2008']
    """
    def __init__(self, csm_info):
        self.seed = csm_info.seed
        self.csm_info = csm_info
        self.num_samples = csm_info.num_samples
        self.gsim_by_trt = []  # rlz.ordinal -> {trt: gsim}
        self.rlzs_by_smodel = {sm.ordinal: [] for sm in csm_info.source_models}

    def get_rlzs_by_gsim(self, trt_or_grp_id, sm_id=None):
        """
        :param trt_or_grp_id: a tectonic region type or a source group ID
        :param sm_id: source model ordinal (or None)
        :returns: a dictionary gsim -> rlzs
        """
        if isinstance(trt_or_grp_id, (int, U32)):  # grp_id
            trt = self.csm_info.trt_by_grp[trt_or_grp_id]
            sm_id = self.csm_info.get_sm_by_grp()[trt_or_grp_id]
        else:  # assume TRT string
            trt = trt_or_grp_id
        acc = collections.defaultdict(list)
        if sm_id is None:  # full dictionary
            for rlz, gsim_by_trt in zip(self.realizations, self.gsim_by_trt):
                acc[gsim_by_trt[trt]].append(rlz.ordinal)
        else:  # dictionary for the selected source model
            for rlz in self.rlzs_by_smodel[sm_id]:
                gsim_by_trt = self.gsim_by_trt[rlz.ordinal]
                try:  # if there is a single TRT
                    [gsim] = gsim_by_trt.values()
                except ValueError:  # there is more than 1 TRT
                    gsim = gsim_by_trt[trt]
                acc[gsim].append(rlz.ordinal)
        return {gsim: numpy.array(acc[gsim], dtype=U16)
                for gsim in sorted(acc)}

    def by_grp(self):
        """
        :returns: a dictionary grp -> rlzis
        """
        dic = {}  # grp -> [(gsim_idx, rlzis), ...]
        for sm in self.csm_info.source_models:
            for sg in sm.src_groups:
                if not sg.eff_ruptures:
                    continue
                rlzs_by_gsim = self.get_rlzs_by_gsim(sg.trt, sm.ordinal)
                if not rlzs_by_gsim:
                    continue
                dic['grp-%02d' % sg.id] = numpy.array(
                    list(rlzs_by_gsim.values()))
        return dic

    def _init(self):
        """
        Finalize the initialization of the RlzsAssoc object by setting
        the (reduced) weights of the realizations.
        """
        if self.num_samples:
            assert len(self.realizations) == self.num_samples, (
                len(self.realizations), self.num_samples)
            tot_weight = sum(rlz.weight for rlz in self.realizations)
            for rlz in self.realizations:
                rlz.weight /= tot_weight
        else:
            tot_weight = sum(rlz.weight for rlz in self.realizations)
            if tot_weight == 0:
                raise ValueError('All realizations have zero weight??')
            elif abs(tot_weight - 1) > 1E-8:
                # this may happen for rounding errors or because of the
                # logic tree reduction; we ensure the sum of the weights is 1
                for rlz in self.realizations:
                    rlz.weight = rlz.weight / tot_weight

    @property
    def realizations(self):
        """Flat list with all the realizations"""
        return sum(self.rlzs_by_smodel.values(), [])

    @property
    def weights(self):
        """Array with the weight of the realizations"""
        return numpy.array([rlz.weight for rlz in self.realizations])

    def combine_pmaps(self, pmap_by_grp):
        """
        :param pmap_by_grp: dictionary group string -> probability map
        :returns: a list of probability maps, one per realization
        """
        grp = list(pmap_by_grp)[0]  # pmap_by_grp must be non-empty
        num_levels = pmap_by_grp[grp].shape_y
        pmaps = [probability_map.ProbabilityMap(num_levels, 1)
                 for _ in self.realizations]
        array = self.by_grp()
        for grp in pmap_by_grp:
            for gsim_idx, rlzis in enumerate(array[grp]):
                pmap = pmap_by_grp[grp].extract(gsim_idx)
                for rlzi in rlzis:
                    pmaps[rlzi] |= pmap
        return pmaps

    def compute_pmap_stats(self, pmap_by_grp, statfuncs):
        """
        :param pmap_by_grp: dictionary group string -> probability map
        :param statfuncs: a list of statistical functions
        :returns: a probability map containing all statistics
        """
        pmaps = self.combine_pmaps(pmap_by_grp)
        return stats.compute_pmap_stats(pmaps, statfuncs, self.weights)

    def get_rlz(self, rlzstr):
        """
        Get a Realization instance for a string of the form 'rlz-\d+'
        """
        mo = re.match('rlz-(\d+)', rlzstr)
        if not mo:
            return
        return self.realizations[int(mo.group(1))]

    def _add_realizations(self, offset, lt_model, all_trts, gsim_rlzs):
        idx = numpy.arange(offset, offset + len(gsim_rlzs))
        rlzs = []
        for i, gsim_rlz in enumerate(gsim_rlzs):
            weight = float(lt_model.weight) * float(gsim_rlz.weight)
            rlz = LtRealization(idx[i], lt_model.path, gsim_rlz, weight)
            self.gsim_by_trt.append(dict(zip(all_trts, gsim_rlz.value)))
            rlzs.append(rlz)
        self.rlzs_by_smodel[lt_model.ordinal] = rlzs

    def __repr__(self):
        pairs = []
        dic = self.by_grp()
        size = sum(len(dic[grp]) for grp in dic)
        for grp in sorted(dic):
            grp_id = int(grp[4:])
            gsims = self.csm_info.get_gsims(grp_id)
            for gsim_idx, rlzis in enumerate(dic[grp]):
                if len(rlzis) > 10:  # short representation
                    rlzis = ['%d realizations' % len(rlzis)]
                pairs.append(('%s,%s' % (grp_id, gsims[gsim_idx]), rlzis))
        return '<%s(size=%d, rlzs=%d)\n%s>' % (
            self.__class__.__name__, size, len(self.realizations),
            '\n'.join('%s: %s' % pair for pair in pairs))

def accept_path(path, ref_path):
    """
    :param path: a logic tree path (list or tuple of strings)
    :param ref_path: reference logic tree path
    :returns: True if `path` is consistent with `ref_path`, False otherwise

    >>> accept_path(['SM2'], ('SM2', 'a3b1'))
    False
    >>> accept_path(['SM2', '@'], ('SM2', 'a3b1'))
    True
    >>> accept_path(['@', 'a3b1'], ('SM2', 'a3b1'))
    True
    >>> accept_path('@@', ('SM2', 'a3b1'))
    True
    """
    if len(path) != len(ref_path):
        return False
    for a, b in zip(path, ref_path):
        if a != '@' and a != b:
            return False
    return True

def get_rlzs_assoc(cinfo, sm_lt_path=None, trts=None):
    """
    :param cinfo: a :class:`openquake.commonlib.source.CompositionInfo`
    :param sm_lt_path: logic tree path tuple used to select a source model
    :param trts: tectonic region types to accept
    """
    assoc = RlzsAssoc(cinfo)
    offset = 0
    trtset = set(cinfo.gsim_lt.tectonic_region_types)
    for smodel in cinfo.source_models:
        # discard source models with non-acceptable lt_path
        if sm_lt_path and not accept_path(smodel.path, sm_lt_path):
            continue

        # collect the effective tectonic region types and ruptures
        trts_ = set()
        for sg in smodel.src_groups:
            if sg.eff_ruptures:
                if (trts and sg.trt in trts) or not trts:
                    trts_.add(sg.trt)

        # recompute the GSIM logic tree if needed
        if trtset != trts_:
            before = cinfo.gsim_lt.get_num_paths()
            gsim_lt = cinfo.gsim_lt.reduce(trts_)
            after = gsim_lt.get_num_paths()
            if sm_lt_path and before > after:
                # print the warning only when saving the logic tree,
                # i.e. when called with sm_lt_path in store_csm_info
                logging.warn('Reducing the logic tree of %s from %d to %d '
                             'realizations', smodel.name, before, after)
            gsim_rlzs = list(gsim_lt)
            all_trts = gsim_lt.all_trts
        else:
            gsim_rlzs = cinfo.gsim_rlzs
            all_trts = cinfo.gsim_lt.all_trts

        rlzs = cinfo._get_rlzs(smodel, gsim_rlzs, cinfo.seed + offset)
        assoc._add_realizations(offset, smodel, all_trts, rlzs)
        offset += len(rlzs)

    if assoc.realizations:
        assoc._init()
    return assoc
<|endoftext|>


<commit_before>#   Copyright 2012-2013 OpenStack, LLC.
#
#   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 logging

from openstackclient.common import exceptions
from openstackclient.common import utils

LOG = logging.getLogger(__name__)

DEFAULT_API_VERSION = '2'
API_VERSION_OPTION = 'os_compute_api_version'
API_NAME = 'compute'
API_VERSIONS = {
    "2": "novaclient.client",
}

# Save the microversion if in use
_compute_api_version = None

def make_client(instance):
    """Returns a compute service client."""

    # Defer client imports until we actually need them
    from novaclient import client as nova_client
    from novaclient import extension
    try:
        from novaclient.v2.contrib import list_extensions
    except ImportError:
        from novaclient.v1_1.contrib import list_extensions

    compute_client = nova_client.get_client_class(
        instance._api_version[API_NAME],
    )
    LOG.debug('Instantiating compute client: %s', compute_client)

    # Set client http_log_debug to True if verbosity level is high enough
    http_log_debug = utils.get_effective_log_level() <= logging.DEBUG

    extensions = [extension.Extension('list_extensions', list_extensions)]

    # Remember interface only if it is set
    kwargs = utils.build_kwargs_dict('endpoint_type', instance._interface)

    if _compute_api_version is not None:
        kwargs.update({'api_version': _compute_api_version})

    client = compute_client(
        session=instance.session,
        extensions=extensions,
        http_log_debug=http_log_debug,
        timings=instance.timing,
        region_name=instance._region_name,
        **kwargs
    )

    return client

def build_option_parser(parser):
    """Hook to add global options"""
    parser.add_argument(
        '--os-compute-api-version',
        metavar='<compute-api-version>',
        default=utils.env('OS_COMPUTE_API_VERSION'),
        help='Compute API version, default=' +
             DEFAULT_API_VERSION +
             ' (Env: OS_COMPUTE_API_VERSION)')
    return parser

def check_api_version(check_version):
    """Validate version supplied by user

    Returns:
    * True if version is OK
    * False if the version has not been checked and the previous plugin
      check should be performed
    * throws an exception if the version is no good

    TODO(dtroyer): make the exception thrown a version-related one
    """

    # Defer client imports until we actually need them
    try:
        from novaclient import api_versions
    except ImportError:
        # Retain previous behaviour
        return False

    import novaclient

    global _compute_api_version

    # Copy some logic from novaclient 2.27.0 for basic version detection
    # NOTE(dtroyer): This is only enough to resume operations using API
    #                version 2.0 or any valid version supplied by the user.
    _compute_api_version = api_versions.get_api_version(check_version)

    if _compute_api_version > api_versions.APIVersion("2.0"):
        if not _compute_api_version.matches(
            novaclient.API_MIN_VERSION,
            novaclient.API_MAX_VERSION,
        ):
            raise exceptions.CommandError(
                "versions supported by client: %s - %s" % (
                    novaclient.API_MIN_VERSION.get_string(),
                    novaclient.API_MAX_VERSION.get_string(),
                ),
            )
    return True
<commit_msg>Use novaclient.client.Client for initialization Nova client<commit_after>#   Copyright 2012-2013 OpenStack, LLC.
#
#   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 logging

from openstackclient.common import exceptions
from openstackclient.common import utils

LOG = logging.getLogger(__name__)

DEFAULT_API_VERSION = '2'
API_VERSION_OPTION = 'os_compute_api_version'
API_NAME = 'compute'
API_VERSIONS = {
    "2": "novaclient.client",
}

# Save the microversion if in use
_compute_api_version = None

def make_client(instance):
    """Returns a compute service client."""

    # Defer client imports until we actually need them
    from novaclient import client as nova_client
    from novaclient import extension
    try:
        from novaclient.v2.contrib import list_extensions
    except ImportError:
        from novaclient.v1_1.contrib import list_extensions

    if _compute_api_version is not None:
        version = _compute_api_version
    else:
        version = instance._api_version[API_NAME]

    LOG.debug('Instantiating compute client for V%s' % version)

    # Set client http_log_debug to True if verbosity level is high enough
    http_log_debug = utils.get_effective_log_level() <= logging.DEBUG

    extensions = [extension.Extension('list_extensions', list_extensions)]

    # Remember interface only if it is set
    kwargs = utils.build_kwargs_dict('endpoint_type', instance._interface)

    client = nova_client.Client(
        version,
        session=instance.session,
        extensions=extensions,
        http_log_debug=http_log_debug,
        timings=instance.timing,
        region_name=instance._region_name,
        **kwargs
    )

    return client

def build_option_parser(parser):
    """Hook to add global options"""
    parser.add_argument(
        '--os-compute-api-version',
        metavar='<compute-api-version>',
        default=utils.env('OS_COMPUTE_API_VERSION'),
        help='Compute API version, default=' +
             DEFAULT_API_VERSION +
             ' (Env: OS_COMPUTE_API_VERSION)')
    return parser

def check_api_version(check_version):
    """Validate version supplied by user

    Returns:
    * True if version is OK
    * False if the version has not been checked and the previous plugin
      check should be performed
    * throws an exception if the version is no good

    TODO(dtroyer): make the exception thrown a version-related one
    """

    # Defer client imports until we actually need them
    try:
        from novaclient import api_versions
    except ImportError:
        # Retain previous behaviour
        return False

    import novaclient

    global _compute_api_version

    # Copy some logic from novaclient 2.27.0 for basic version detection
    # NOTE(dtroyer): This is only enough to resume operations using API
    #                version 2.0 or any valid version supplied by the user.
    _compute_api_version = api_versions.get_api_version(check_version)

    if _compute_api_version > api_versions.APIVersion("2.0"):
        if not _compute_api_version.matches(
            novaclient.API_MIN_VERSION,
            novaclient.API_MAX_VERSION,
        ):
            raise exceptions.CommandError(
                "versions supported by client: %s - %s" % (
                    novaclient.API_MIN_VERSION.get_string(),
                    novaclient.API_MAX_VERSION.get_string(),
                ),
            )
    return True
<|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 abc
import logging

import openstack.exceptions
from osc_lib.command import command
from osc_lib import exceptions
import six

from openstackclient.i18n import _

LOG = logging.getLogger(__name__)

@six.add_metaclass(abc.ABCMeta)
class NetworkAndComputeCommand(command.Command):
    """Network and Compute Command

    Command class for commands that support implementation via
    the network or compute endpoint. Such commands have different
    implementations for take_action() and may even have different
    arguments.
    """

    def take_action(self, parsed_args):
        if self.app.client_manager.is_network_endpoint_enabled():
            return self.take_action_network(self.app.client_manager.network,
                                            parsed_args)
        else:
            return self.take_action_compute(self.app.client_manager.compute,
                                            parsed_args)

    def get_parser(self, prog_name):
        LOG.debug('get_parser(%s)', prog_name)
        parser = super(NetworkAndComputeCommand, self).get_parser(prog_name)
        parser = self.update_parser_common(parser)
        LOG.debug('common parser: %s', parser)
        if self.app.client_manager.is_network_endpoint_enabled():
            return self.update_parser_network(parser)
        else:
            return self.update_parser_compute(parser)

    def update_parser_common(self, parser):
        """Default is no updates to parser."""
        return parser

    def update_parser_network(self, parser):
        """Default is no updates to parser."""
        return parser

    def update_parser_compute(self, parser):
        """Default is no updates to parser."""
        return parser

    @abc.abstractmethod
    def take_action_network(self, client, parsed_args):
        """Override to do something useful."""
        pass

    @abc.abstractmethod
    def take_action_compute(self, client, parsed_args):
        """Override to do something useful."""
        pass

@six.add_metaclass(abc.ABCMeta)
class NetworkAndComputeDelete(NetworkAndComputeCommand):
    """Network and Compute Delete

    Delete class for commands that support implementation via
    the network or compute endpoint. Such commands have different
    implementations for take_action() and may even have different
    arguments. This class supports bulk deletion, and error handling
    following the rules in doc/source/command-errors.rst.
    """

    def take_action(self, parsed_args):
        ret = 0
        resources = getattr(parsed_args, self.resource, [])

        for r in resources:
            self.r = r
            try:
                if self.app.client_manager.is_network_endpoint_enabled():
                    self.take_action_network(self.app.client_manager.network,
                                             parsed_args)
                else:
                    self.take_action_compute(self.app.client_manager.compute,
                                             parsed_args)
            except Exception as e:
                msg = _("Failed to delete %(resource)s with name or ID "
                        "'%(name_or_id)s': %(e)s") % {
                            "resource": self.resource,
                            "name_or_id": r,
                            "e": e,
                }
                LOG.error(msg)
                ret += 1

        if ret:
            total = len(resources)
            msg = _("%(num)s of %(total)s %(resource)ss failed to delete.") % {
                "num": ret,
                "total": total,
                "resource": self.resource,
            }
            raise exceptions.CommandError(msg)

@six.add_metaclass(abc.ABCMeta)
class NetworkAndComputeLister(command.Lister):
    """Network and Compute Lister

    Lister class for commands that support implementation via
    the network or compute endpoint. Such commands have different
    implementations for take_action() and may even have different
    arguments.
    """

    def take_action(self, parsed_args):
        if self.app.client_manager.is_network_endpoint_enabled():
            return self.take_action_network(self.app.client_manager.network,
                                            parsed_args)
        else:
            return self.take_action_compute(self.app.client_manager.compute,
                                            parsed_args)

    def get_parser(self, prog_name):
        LOG.debug('get_parser(%s)', prog_name)
        parser = super(NetworkAndComputeLister, self).get_parser(prog_name)
        parser = self.update_parser_common(parser)
        LOG.debug('common parser: %s', parser)
        if self.app.client_manager.is_network_endpoint_enabled():
            return self.update_parser_network(parser)
        else:
            return self.update_parser_compute(parser)

    def update_parser_common(self, parser):
        """Default is no updates to parser."""
        return parser

    def update_parser_network(self, parser):
        """Default is no updates to parser."""
        return parser

    def update_parser_compute(self, parser):
        """Default is no updates to parser."""
        return parser

    @abc.abstractmethod
    def take_action_network(self, client, parsed_args):
        """Override to do something useful."""
        pass

    @abc.abstractmethod
    def take_action_compute(self, client, parsed_args):
        """Override to do something useful."""
        pass

@six.add_metaclass(abc.ABCMeta)
class NetworkAndComputeShowOne(command.ShowOne):
    """Network and Compute ShowOne

    ShowOne class for commands that support implementation via
    the network or compute endpoint. Such commands have different
    implementations for take_action() and may even have different
    arguments.
    """

    def take_action(self, parsed_args):
        try:
            if self.app.client_manager.is_network_endpoint_enabled():
                return self.take_action_network(
                    self.app.client_manager.network, parsed_args)
            else:
                return self.take_action_compute(
                    self.app.client_manager.compute, parsed_args)
        except openstack.exceptions.HttpException as exc:
            msg = _("Error while executing command: %s") % exc.message
            raise exceptions.CommandError(msg)

    def get_parser(self, prog_name):
        LOG.debug('get_parser(%s)', prog_name)
        parser = super(NetworkAndComputeShowOne, self).get_parser(prog_name)
        parser = self.update_parser_common(parser)
        LOG.debug('common parser: %s', parser)
        if self.app.client_manager.is_network_endpoint_enabled():
            return self.update_parser_network(parser)
        else:
            return self.update_parser_compute(parser)

    def update_parser_common(self, parser):
        """Default is no updates to parser."""
        return parser

    def update_parser_network(self, parser):
        """Default is no updates to parser."""
        return parser

    def update_parser_compute(self, parser):
        """Default is no updates to parser."""
        return parser

    @abc.abstractmethod
    def take_action_network(self, client, parsed_args):
        """Override to do something useful."""
        pass

    @abc.abstractmethod
    def take_action_compute(self, client, parsed_args):
        """Override to do something useful."""
        pass
<commit_msg>Show detailed message of neutron exception<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 abc
import logging

import openstack.exceptions
from osc_lib.command import command
from osc_lib import exceptions
import six

from openstackclient.i18n import _

LOG = logging.getLogger(__name__)

@six.add_metaclass(abc.ABCMeta)
class NetworkAndComputeCommand(command.Command):
    """Network and Compute Command

    Command class for commands that support implementation via
    the network or compute endpoint. Such commands have different
    implementations for take_action() and may even have different
    arguments.
    """

    def take_action(self, parsed_args):
        if self.app.client_manager.is_network_endpoint_enabled():
            return self.take_action_network(self.app.client_manager.network,
                                            parsed_args)
        else:
            return self.take_action_compute(self.app.client_manager.compute,
                                            parsed_args)

    def get_parser(self, prog_name):
        LOG.debug('get_parser(%s)', prog_name)
        parser = super(NetworkAndComputeCommand, self).get_parser(prog_name)
        parser = self.update_parser_common(parser)
        LOG.debug('common parser: %s', parser)
        if self.app.client_manager.is_network_endpoint_enabled():
            return self.update_parser_network(parser)
        else:
            return self.update_parser_compute(parser)

    def update_parser_common(self, parser):
        """Default is no updates to parser."""
        return parser

    def update_parser_network(self, parser):
        """Default is no updates to parser."""
        return parser

    def update_parser_compute(self, parser):
        """Default is no updates to parser."""
        return parser

    @abc.abstractmethod
    def take_action_network(self, client, parsed_args):
        """Override to do something useful."""
        pass

    @abc.abstractmethod
    def take_action_compute(self, client, parsed_args):
        """Override to do something useful."""
        pass

@six.add_metaclass(abc.ABCMeta)
class NetworkAndComputeDelete(NetworkAndComputeCommand):
    """Network and Compute Delete

    Delete class for commands that support implementation via
    the network or compute endpoint. Such commands have different
    implementations for take_action() and may even have different
    arguments. This class supports bulk deletion, and error handling
    following the rules in doc/source/command-errors.rst.
    """

    def take_action(self, parsed_args):
        ret = 0
        resources = getattr(parsed_args, self.resource, [])

        for r in resources:
            self.r = r
            try:
                if self.app.client_manager.is_network_endpoint_enabled():
                    self.take_action_network(self.app.client_manager.network,
                                             parsed_args)
                else:
                    self.take_action_compute(self.app.client_manager.compute,
                                             parsed_args)
            except Exception as e:
                msg = _("Failed to delete %(resource)s with name or ID "
                        "'%(name_or_id)s': %(e)s") % {
                            "resource": self.resource,
                            "name_or_id": r,
                            "e": e,
                }
                LOG.error(msg)
                ret += 1

        if ret:
            total = len(resources)
            msg = _("%(num)s of %(total)s %(resource)ss failed to delete.") % {
                "num": ret,
                "total": total,
                "resource": self.resource,
            }
            raise exceptions.CommandError(msg)

@six.add_metaclass(abc.ABCMeta)
class NetworkAndComputeLister(command.Lister):
    """Network and Compute Lister

    Lister class for commands that support implementation via
    the network or compute endpoint. Such commands have different
    implementations for take_action() and may even have different
    arguments.
    """

    def take_action(self, parsed_args):
        if self.app.client_manager.is_network_endpoint_enabled():
            return self.take_action_network(self.app.client_manager.network,
                                            parsed_args)
        else:
            return self.take_action_compute(self.app.client_manager.compute,
                                            parsed_args)

    def get_parser(self, prog_name):
        LOG.debug('get_parser(%s)', prog_name)
        parser = super(NetworkAndComputeLister, self).get_parser(prog_name)
        parser = self.update_parser_common(parser)
        LOG.debug('common parser: %s', parser)
        if self.app.client_manager.is_network_endpoint_enabled():
            return self.update_parser_network(parser)
        else:
            return self.update_parser_compute(parser)

    def update_parser_common(self, parser):
        """Default is no updates to parser."""
        return parser

    def update_parser_network(self, parser):
        """Default is no updates to parser."""
        return parser

    def update_parser_compute(self, parser):
        """Default is no updates to parser."""
        return parser

    @abc.abstractmethod
    def take_action_network(self, client, parsed_args):
        """Override to do something useful."""
        pass

    @abc.abstractmethod
    def take_action_compute(self, client, parsed_args):
        """Override to do something useful."""
        pass

@six.add_metaclass(abc.ABCMeta)
class NetworkAndComputeShowOne(command.ShowOne):
    """Network and Compute ShowOne

    ShowOne class for commands that support implementation via
    the network or compute endpoint. Such commands have different
    implementations for take_action() and may even have different
    arguments.
    """

    def take_action(self, parsed_args):
        try:
            if self.app.client_manager.is_network_endpoint_enabled():
                return self.take_action_network(
                    self.app.client_manager.network, parsed_args)
            else:
                return self.take_action_compute(
                    self.app.client_manager.compute, parsed_args)
        except openstack.exceptions.HttpException as exc:
            msg = _("Error while executing command: %s") % exc.message
            if exc.details:
                msg += ", " + six.text_type(exc.details)
            raise exceptions.CommandError(msg)

    def get_parser(self, prog_name):
        LOG.debug('get_parser(%s)', prog_name)
        parser = super(NetworkAndComputeShowOne, self).get_parser(prog_name)
        parser = self.update_parser_common(parser)
        LOG.debug('common parser: %s', parser)
        if self.app.client_manager.is_network_endpoint_enabled():
            return self.update_parser_network(parser)
        else:
            return self.update_parser_compute(parser)

    def update_parser_common(self, parser):
        """Default is no updates to parser."""
        return parser

    def update_parser_network(self, parser):
        """Default is no updates to parser."""
        return parser

    def update_parser_compute(self, parser):
        """Default is no updates to parser."""
        return parser

    @abc.abstractmethod
    def take_action_network(self, client, parsed_args):
        """Override to do something useful."""
        pass

    @abc.abstractmethod
    def take_action_compute(self, client, parsed_args):
        """Override to do something useful."""
        pass
<|endoftext|>


<commit_before>import logging
import logging.config
import os
import sys

from appdirs import user_log_dir

from .app_settings import DEV_MODE, PROJECT_NAME, PROJECT_AUTHOR

### Where to store project-level logs
PROJECT_LOG_DIR = user_log_dir(appname=PROJECT_NAME, appauthor=PROJECT_AUTHOR)
PROJECT_LOG_FILE = os.path.join(PROJECT_LOG_DIR, 'osfoffline.log')

### Logging configuration
CONSOLE_FORMATTER = {
    '()': 'colorlog.ColoredFormatter',
    'format': '%(cyan)s[%(asctime)s]%(log_color)s[%(threadName)s][%(filename)s][%(levelname)s][%(name)s]: %(reset)s%(message)s'
}

FILE_FORMATTER = '[%(asctime)s][%(threadName)s][%(filename)s][%(levelname)s][%(name)s]: %(message)s'

if DEV_MODE is True:
    log_level = 'DEBUG'
else:
    log_level = 'INFO'

DEFAULT_LOGGING_CONFIG = {
    'version': 1,
    'disable_existing_loggers': False,
    'formatters': {
        'console': CONSOLE_FORMATTER,
        'file_log': {'format': FILE_FORMATTER}
    },
    'handlers': {
        'console': {
            'class': 'logging.StreamHandler',
            'level': log_level,
            'formatter': 'console'
        },
        'syslog': {
            'class': 'logging.handlers.SysLogHandler',
            'level': log_level
        },
        'logfile': {
            'class': 'logging.FileHandler',
            'level': log_level,
            'filename': PROJECT_LOG_FILE,
            'formatter': 'file_log'
        },
    },
    'loggers': {
        '': {
            'handlers': ['console'],
            'level': log_level,
            'propagate': False
        }
    },
    'root': {
        'level': log_level,
        'handlers': ['console', 'logfile']
    }
}

def capture_exceptions(exc_type, exc_value, tb):
    """Ensure that uncaught exceptions are logged"""
    logging.exception('Uncaught exception: ', exc_info=(exc_type, exc_value, tb))

<commit_msg>fix the deploy import<commit_after>import logging
import logging.config
import os
import colorlog

from appdirs import user_log_dir

from .app_settings import DEV_MODE, PROJECT_NAME, PROJECT_AUTHOR

### Where to store project-level logs
PROJECT_LOG_DIR = user_log_dir(appname=PROJECT_NAME, appauthor=PROJECT_AUTHOR)
PROJECT_LOG_FILE = os.path.join(PROJECT_LOG_DIR, 'osfoffline.log')

### Logging configuration
CONSOLE_FORMATTER = {
    '()': 'colorlog.ColoredFormatter',
    'format': '%(cyan)s[%(asctime)s]%(log_color)s[%(threadName)s][%(filename)s][%(levelname)s][%(name)s]: %(reset)s%(message)s'
}

FILE_FORMATTER = '[%(asctime)s][%(threadName)s][%(filename)s][%(levelname)s][%(name)s]: %(message)s'

if DEV_MODE is True:
    log_level = 'DEBUG'
else:
    log_level = 'INFO'

DEFAULT_LOGGING_CONFIG = {
    'version': 1,
    'disable_existing_loggers': False,
    'formatters': {
        'console': CONSOLE_FORMATTER,
        'file_log': {'format': FILE_FORMATTER}
    },
    'handlers': {
        'console': {
            'class': 'logging.StreamHandler',
            'level': log_level,
            'formatter': 'console'
        },
        'syslog': {
            'class': 'logging.handlers.SysLogHandler',
            'level': log_level
        },
        'logfile': {
            'class': 'logging.FileHandler',
            'level': log_level,
            'filename': PROJECT_LOG_FILE,
            'formatter': 'file_log'
        },
    },
    'loggers': {
        '': {
            'handlers': ['console'],
            'level': log_level,
            'propagate': False
        }
    },
    'root': {
        'level': log_level,
        'handlers': ['console', 'logfile']
    }
}

def capture_exceptions(exc_type, exc_value, tb):
    """Ensure that uncaught exceptions are logged"""
    logging.exception('Uncaught exception: ', exc_info=(exc_type, exc_value, tb))

<|endoftext|>


<commit_before>""" http://docs.zope.org/zope.testrunner/#some-useful-command-line-options-to-get-you-started
"""
import unittest

import urllib
import contextlib
import json

from ott.utils.parse import csv_reader

HOST="localhost:44444"
HOST="maps7.trimet.org/ride_ws"

class TestGeoCoder(unittest.TestCase):
    def setUp(self):
        here = csv_reader.Csv.get_dirname(__file__)
        self.csv_file = csv_reader.Csv('geocodes.csv', here)
        self.test_data = self.csv_file.open()

    def tearDown(self):
        self.csv_file.close()
        pass

    def test_zoo(self):
        url = get_url('geocode', 'place=zoo')
        j = call_url(url)
        s = json.dumps(j)
        self.assertRegexpMatches(s,"-122.71")
        self.assertRegexpMatches(s,"45.51")

    def test_geocode_csv_data(self):
        for d in self.test_data:
            u = get_url('geostr', 'place=' + d['name'])
            s = call_url_text(u)
            self.assertRegexpMatches(s,d['lat'].strip())
            self.assertRegexpMatches(s,d['lon'].strip())

def get_url(svc_name, params=None):
    ret_val = "http://{0}/{1}".format(HOST, svc_name)
    if params:
        ret_val = "{0}?{1}".format(ret_val, params)
    return ret_val

def call_url(url):
    with contextlib.closing(urllib.urlopen(url)) as f:
        ret_json = json.load(f)
    return ret_json

def call_url_text(url):
    return urllib.urlopen(url).read()
<commit_msg>fix(py3): fix urllib<commit_after>""" http://docs.zope.org/zope.testrunner/#some-useful-command-line-options-to-get-you-started
"""
import unittest
import contextlib
import json

from ott.utils.compat_2_to_3 import *
from ott.utils.parse import csv_reader

HOST="localhost:44444"
HOST="maps7.trimet.org/ride_ws"

class TestGeoCoder(unittest.TestCase):
    def setUp(self):
        here = csv_reader.Csv.get_dirname(__file__)
        self.csv_file = csv_reader.Csv('geocodes.csv', here)
        self.test_data = self.csv_file.open()

    def tearDown(self):
        self.csv_file.close()
        pass

    def test_zoo(self):
        url = get_url('geocode', 'place=zoo')
        j = call_url(url)
        s = json.dumps(j)
        self.assertRegexpMatches(s,"-122.71")
        self.assertRegexpMatches(s,"45.51")

    def test_geocode_csv_data(self):
        for d in self.test_data:
            u = get_url('geostr', 'place=' + d['name'])
            s = call_url_text(u)
            self.assertRegexpMatches(s,d['lat'].strip())
            self.assertRegexpMatches(s,d['lon'].strip())

def get_url(svc_name, params=None):
    ret_val = "http://{0}/{1}".format(HOST, svc_name)
    if params:
        ret_val = "{0}?{1}".format(ret_val, params)
    return ret_val

def call_url(url):
    with contextlib.closing(urllib.urlopen(url)) as f:
        ret_json = json.load(f)
    return ret_json

def call_url_text(url):
    return urllib.urlopen(url).read()
<|endoftext|>


<commit_before>from ovp_projects import models
from ovp_projects.models.apply import apply_status_choices

from ovp_users.serializers import UserPublicRetrieveSerializer, UserApplyRetrieveSerializer

from rest_framework import serializers

class ApplyCreateSerializer(serializers.ModelSerializer):
  email = serializers.EmailField(required=False)

  class Meta:
    model = models.Apply
    fields = ['username', 'email', 'phone', 'project', 'user']

class ApplyUpdateSerializer(serializers.ModelSerializer):
  status = serializers.ChoiceField(choices=apply_status_choices)

  class Meta:
    model = models.Apply
    fields = ['status']

class ApplyRetrieveSerializer(serializers.ModelSerializer):
  user = UserApplyRetrieveSerializer()
  status = serializers.SerializerMethodField()

  class Meta:
    model = models.Apply
    fields = ['id', 'email', 'date', 'canceled', 'canceled_date', 'status', 'user']

  def get_status(self, object):
    return object.get_status_display()

class ProjectAppliesSerializer(serializers.ModelSerializer):
  user = UserPublicRetrieveSerializer()

  class Meta:
    model = models.Apply
    fields = ['date', 'user']
<commit_msg>Add username, email and phone on Apply serializer<commit_after>from ovp_projects import models
from ovp_projects.models.apply import apply_status_choices

from ovp_users.serializers import UserPublicRetrieveSerializer, UserApplyRetrieveSerializer

from rest_framework import serializers

class ApplyCreateSerializer(serializers.ModelSerializer):
  email = serializers.EmailField(required=False)

  class Meta:
    model = models.Apply
    fields = ['username', 'email', 'phone', 'project', 'user']

class ApplyUpdateSerializer(serializers.ModelSerializer):
  status = serializers.ChoiceField(choices=apply_status_choices)

  class Meta:
    model = models.Apply
    fields = ['status']

class ApplyRetrieveSerializer(serializers.ModelSerializer):
  user = UserApplyRetrieveSerializer()
  status = serializers.SerializerMethodField()

  class Meta:
    model = models.Apply
    fields = ['id', 'email', 'username', 'phone', 'date', 'canceled', 'canceled_date', 'status', 'user']

  def get_status(self, object):
    return object.get_status_display()

class ProjectAppliesSerializer(serializers.ModelSerializer):
  user = UserPublicRetrieveSerializer()

  class Meta:
    model = models.Apply
    fields = ['date', 'user']
<|endoftext|>


<commit_before>"""
The basic idea behind objective is to build a tree like structure in terms of classes and descriptors which resolve
either the :py:obj:`Item` or the :py:obj:`Node`.

De/serialization is done by traversing over the tree and take the
"""

import functools
from collections import OrderedDict

import six

from . import exc, values

class reify(object):

    """
    create a property and set value into instance dict
    https://github.com/Pylons/pyramid/blob/master/pyramid/decorator.py
    """

    def __init__(self, wrapped):
        self.wrapped = wrapped
        functools.update_wrapper(self, wrapped)

    def __get__(self, inst, objtype=None):
        if inst is None:
            return self

        val = self.wrapped(inst)
        setattr(inst, self.wrapped.__name__, val)

        return val

class Missing(object):

    """Defines an action to be peformed when the value is missing."""

    def __init__(self, node, environment=None):
        self.node = node
        self.environment = environment

    def __call__(self, value):
        """Just raise a `MissingValue` exception."""

        raise exc.MissingValue(
            self.node,
            value=value,
            msg="Value for `{0}` is missing!".format(self.node.__name__)
        )

class Ignore(Missing):

    """:py:class:`Ignore` will make the deserialization simply ignore the
    missing value."""

    def __call__(self, value):
        """We raise an ``IgnoreValue`` exception."""

        raise exc.IgnoreValue("Ignore `{}`.".format(self.node.__name__))

class Item(object):

    """Declares an item of a mapping to be instantiated."""

    __items__ = []
    """Remembers the order of :py:obj:`Item` instantiation."""

    def __new__(cls, *args, **kwargs):
        inst = super(Item, cls).__new__(cls, *args, **kwargs)

        cls.__items__.append(inst)

        return inst

    def __init__(self, node_class=None, name=None, *args, **kwargs):
        """Prepares node class instantiation.

        :param node_class: the type of the node
        :param name: the explicit name of the node
        :param args: additional arguments for the node instantiation
        :param kwargs: additional keyword arguments for the node instantiation

        """
        self.node_class = node_class
        self.name = name
        self.node_args = args
        self.node_kwargs = kwargs

    def __get__(self, obj, cls=None):
        """Resolve the ``Node`` instance or return the ``Item`` instance."""

        if obj is None:
            # return the node class if accessed over class
            return self.node_class

        return self.node

    def __call__(self, node_class):
        """Decorate a class, which will be setup for instantiation of the node."""

        self.node_class = node_class

        return self

    def __repr__(self):
        return "<{0.__class__.__name__}: {0.name} = {0.node}>".format(self)

    def attach_name(self, name):
        """Attach a name to an item.

        Called by :py:class:`NodeMeta` to attach a name to an item.

        If the item.name is already set the parent name will be ignored.
        So we are able to map certain external names, which might be reserved words
        to varying internal ones.

        """

        if not self.name:
            self.name = name

    @property
    def index(self):
        """:returns: the index of creation of this item."""

        return self.__items__.index(self)

    @reify
    def node(self):
        """Create a :py:class:`Node` instance.

        All args and kwargs are forwarded to the node.

        :returns: a :py:class:`Node` instance
        """

        if self.node_class is None:
            raise ValueError("You have to create an ``Item`` by calling ``__init__`` with ``node_class`` argument"
                             " or by decorating a ``Node`` class.")

        node = self.node_class(*self.node_args, **self.node_kwargs)
        node.__item__ = self

        return node

class NodeMeta(type):

    """Performs ``Node`` instantiation by looking up ``Item`` instances."""

    __node_base__ = None

    def __new__(mcs, name, bases, dct):
        """Collect all ``Item`` instances and add them to the new class."""

        cls = type.__new__(mcs, name, bases, dct)

        # just register our base class so we know it for items collection
        if mcs.__node_base__ is None:
            mcs.__node_base__ = cls

        return cls

    def __init__(cls, name, bases, dct):
        super(NodeMeta, cls).__init__(name, bases, dct)

        # a simple name mapping
        cls.__names__ = OrderedDict()

        # if we don't have a base yet, we ignore possible items
        if cls.__node_base__:
            # inherite from bases
            for base in bases:
                if issubclass(base, cls.__node_base__):
                    cls.__names__.update(base.__names__)

        def key(name_item):
            return name_item[1].index

        # take own items last
        for node_name, item in sorted(
                (name_item for name_item in six.iteritems(dct) if isinstance(name_item[1], Item)),
                key=key
        ):
            if isinstance(item, Item):
                # set name if not already set by Item call
                item.attach_name(node_name)
                cls.__names__[item.name or node_name] = node_name

    def __contains__(cls, name):
        return name in cls.__names__

    def __getitem__(cls, name):
        if name in cls:
            return getattr(cls, cls.__names__[name])

        raise KeyError("`{}` not in {}".format(name, cls))

    def __iter__(cls):
        for name in cls.__names__:
            yield name, getattr(cls, cls.__names__[name])

class Node(six.with_metaclass(NodeMeta)):

    """A node of a tree like structure, which serves as a blueprint for value examination."""

    # the item this node was created by
    __item__ = None

    @property
    def __name__(self):
        return self.__item__ and self.__item__.name or None

    def __contains__(self, name):
        return name in self.__names__

    def __getitem__(self, name):
        """Returns a previously collected ``Item``, which will be a ``Node`` by descriptor magic."""

        if name in self:
            return getattr(self, self.__names__[name])

        raise KeyError("`{}` not in {}".format(name, self))

    def __iter__(self):
        """Iterates over all items and returns appropriate nodes."""

        for name in self.__names__:
            yield name, getattr(self, self.__names__[name])

    def __repr__(self):
        """Represent a Node."""

        return "<{n.__class__.__name__}:{n.__name__} [{items}]>"\
            .format(
                n=self, items=', '.join(sorted(name for name, _ in self))
            )

class Field(Node):

    """A ``Field`` describes the value of a ``Node``.

    It can serialize and deserialize a value. An optional validator sanitizes
    the value after deserializing it.

    """

    # create a validator in the Field
    _validator = None

    def __init__(self, validator=None, **kwargs):
        """Optionally Assigns the validator.

        :param validator: the validator to be used
        :param missing: action to be performed when the value is ``Undefined`` and therefor missing

        """
        super(Field, self).__init__()

        if validator is not None:
            setattr(self, "_validator", validator)

        # this is intentionally in kwargs, so we can also apply ``None`` for missing
        self._missing = kwargs.get('missing', Missing)

        # missing=Ignore shortcut: optional=True
        if 'missing' not in kwargs and kwargs.get('optional', False):
            self._missing = Ignore

    def _resolve_value(self, value, environment=None):
        """Resolve the value.

        Either apply missing or leave the value as is.

        :param value: the value either from deserialize or serialize
        :param environment: an optional environment
        """

        # here we care about Undefined values
        if value == values.Undefined:
            if isinstance(self._missing, type) and issubclass(self._missing, Missing):
                # instantiate the missing thing
                missing = self._missing(self, environment)

                # invoke missing callback
                # the default is to raise a MissingValue() exception
                value = missing(value)

            elif hasattr(self._missing, "__call__"):
                value = self._missing()

            else:
                # we just assign any value
                value = self._missing

        return value

    def _serialize(self, value, environment=None):                # pylint: disable=R0201
        """Serialization worker."""

        return value

    def serialize(self, value, environment=None):
        """Serialze a value into a transportable and interchangeable format.

        The default assumption is that the value is JSON e.g. string or number.
        Some encoders also support datetime by default.

        Serialization should not be validated, since the developer app would be
        bounced, since the mistake comes from there - use unittests for this!

        """
        value = self._resolve_value(value, environment)

        value = self._serialize(value, environment)

        return value

    def _deserialize(self, value, environment=None):              # pylint: disable=R0201
        """Derserialization worker method."""

        return value

    def deserialize(self, value, environment=None):
        """Deserialize a value into a special application specific format or type.

        `value` can be `Missing`, `None` or something else.

        :param value: the value to be deserialized
        :param environment: additional environment
        """

        value = self._resolve_value(value, environment)

        try:
            value = self._deserialize(value, environment)

            if self._validator is not None:
                value = self._validator(self, value, environment)     # pylint: disable=E1102

        except exc.InvalidValue as ex:
            # just reraise
            raise

        except (exc.Invalid, ValueError, TypeError):
            # we convert a bare Invalid into InvalidValue
            raise exc.InvalidValue(self, value=value)

        return value
<commit_msg>add origin to InvalidValue<commit_after>"""
The basic idea behind objective is to build a tree like structure in terms of classes and descriptors which resolve
either the :py:obj:`Item` or the :py:obj:`Node`.

De/serialization is done by traversing over the tree and take the
"""

import functools
from collections import OrderedDict

import six

from . import exc, values

class reify(object):

    """
    create a property and set value into instance dict
    https://github.com/Pylons/pyramid/blob/master/pyramid/decorator.py
    """

    def __init__(self, wrapped):
        self.wrapped = wrapped
        functools.update_wrapper(self, wrapped)

    def __get__(self, inst, objtype=None):
        if inst is None:
            return self

        val = self.wrapped(inst)
        setattr(inst, self.wrapped.__name__, val)

        return val

class Missing(object):

    """Defines an action to be peformed when the value is missing."""

    def __init__(self, node, environment=None):
        self.node = node
        self.environment = environment

    def __call__(self, value):
        """Just raise a `MissingValue` exception."""

        raise exc.MissingValue(
            self.node,
            value=value,
            msg="Value for `{0}` is missing!".format(self.node.__name__)
        )

class Ignore(Missing):

    """:py:class:`Ignore` will make the deserialization simply ignore the
    missing value."""

    def __call__(self, value):
        """We raise an ``IgnoreValue`` exception."""

        raise exc.IgnoreValue("Ignore `{}`.".format(self.node.__name__))

class Item(object):

    """Declares an item of a mapping to be instantiated."""

    __items__ = []
    """Remembers the order of :py:obj:`Item` instantiation."""

    def __new__(cls, *args, **kwargs):
        inst = super(Item, cls).__new__(cls, *args, **kwargs)

        cls.__items__.append(inst)

        return inst

    def __init__(self, node_class=None, name=None, *args, **kwargs):
        """Prepares node class instantiation.

        :param node_class: the type of the node
        :param name: the explicit name of the node
        :param args: additional arguments for the node instantiation
        :param kwargs: additional keyword arguments for the node instantiation

        """
        self.node_class = node_class
        self.name = name
        self.node_args = args
        self.node_kwargs = kwargs

    def __get__(self, obj, cls=None):
        """Resolve the ``Node`` instance or return the ``Item`` instance."""

        if obj is None:
            # return the node class if accessed over class
            return self.node_class

        return self.node

    def __call__(self, node_class):
        """Decorate a class, which will be setup for instantiation of the node."""

        self.node_class = node_class

        return self

    def __repr__(self):
        return "<{0.__class__.__name__}: {0.name} = {0.node}>".format(self)

    def attach_name(self, name):
        """Attach a name to an item.

        Called by :py:class:`NodeMeta` to attach a name to an item.

        If the item.name is already set the parent name will be ignored.
        So we are able to map certain external names, which might be reserved words
        to varying internal ones.

        """

        if not self.name:
            self.name = name

    @property
    def index(self):
        """:returns: the index of creation of this item."""

        return self.__items__.index(self)

    @reify
    def node(self):
        """Create a :py:class:`Node` instance.

        All args and kwargs are forwarded to the node.

        :returns: a :py:class:`Node` instance
        """

        if self.node_class is None:
            raise ValueError("You have to create an ``Item`` by calling ``__init__`` with ``node_class`` argument"
                             " or by decorating a ``Node`` class.")

        node = self.node_class(*self.node_args, **self.node_kwargs)
        node.__item__ = self

        return node

class NodeMeta(type):

    """Performs ``Node`` instantiation by looking up ``Item`` instances."""

    __node_base__ = None

    def __new__(mcs, name, bases, dct):
        """Collect all ``Item`` instances and add them to the new class."""

        cls = type.__new__(mcs, name, bases, dct)

        # just register our base class so we know it for items collection
        if mcs.__node_base__ is None:
            mcs.__node_base__ = cls

        return cls

    def __init__(cls, name, bases, dct):
        super(NodeMeta, cls).__init__(name, bases, dct)

        # a simple name mapping
        cls.__names__ = OrderedDict()

        # if we don't have a base yet, we ignore possible items
        if cls.__node_base__:
            # inherite from bases
            for base in bases:
                if issubclass(base, cls.__node_base__):
                    cls.__names__.update(base.__names__)

        def key(name_item):
            return name_item[1].index

        # take own items last
        for node_name, item in sorted(
                (name_item for name_item in six.iteritems(dct) if isinstance(name_item[1], Item)),
                key=key
        ):
            if isinstance(item, Item):
                # set name if not already set by Item call
                item.attach_name(node_name)
                cls.__names__[item.name or node_name] = node_name

    def __contains__(cls, name):
        return name in cls.__names__

    def __getitem__(cls, name):
        if name in cls:
            return getattr(cls, cls.__names__[name])

        raise KeyError("`{}` not in {}".format(name, cls))

    def __iter__(cls):
        for name in cls.__names__:
            yield name, getattr(cls, cls.__names__[name])

class Node(six.with_metaclass(NodeMeta)):

    """A node of a tree like structure, which serves as a blueprint for value examination."""

    # the item this node was created by
    __item__ = None

    @property
    def __name__(self):
        return self.__item__ and self.__item__.name or None

    def __contains__(self, name):
        return name in self.__names__

    def __getitem__(self, name):
        """Returns a previously collected ``Item``, which will be a ``Node`` by descriptor magic."""

        if name in self:
            return getattr(self, self.__names__[name])

        raise KeyError("`{}` not in {}".format(name, self))

    def __iter__(self):
        """Iterates over all items and returns appropriate nodes."""

        for name in self.__names__:
            yield name, getattr(self, self.__names__[name])

    def __repr__(self):
        """Represent a Node."""

        return "<{n.__class__.__name__}:{n.__name__} [{items}]>"\
            .format(
                n=self, items=', '.join(sorted(name for name, _ in self))
            )

class Field(Node):

    """A ``Field`` describes the value of a ``Node``.

    It can serialize and deserialize a value. An optional validator sanitizes
    the value after deserializing it.

    """

    # create a validator in the Field
    _validator = None

    def __init__(self, validator=None, **kwargs):
        """Optionally Assigns the validator.

        :param validator: the validator to be used
        :param missing: action to be performed when the value is ``Undefined`` and therefor missing

        """
        super(Field, self).__init__()

        if validator is not None:
            setattr(self, "_validator", validator)

        # this is intentionally in kwargs, so we can also apply ``None`` for missing
        self._missing = kwargs.get('missing', Missing)

        # missing=Ignore shortcut: optional=True
        if 'missing' not in kwargs and kwargs.get('optional', False):
            self._missing = Ignore

    def _resolve_value(self, value, environment=None):
        """Resolve the value.

        Either apply missing or leave the value as is.

        :param value: the value either from deserialize or serialize
        :param environment: an optional environment
        """

        # here we care about Undefined values
        if value == values.Undefined:
            if isinstance(self._missing, type) and issubclass(self._missing, Missing):
                # instantiate the missing thing
                missing = self._missing(self, environment)

                # invoke missing callback
                # the default is to raise a MissingValue() exception
                value = missing(value)

            elif hasattr(self._missing, "__call__"):
                value = self._missing()

            else:
                # we just assign any value
                value = self._missing

        return value

    def _serialize(self, value, environment=None):                # pylint: disable=R0201
        """Serialization worker."""

        return value

    def serialize(self, value, environment=None):
        """Serialze a value into a transportable and interchangeable format.

        The default assumption is that the value is JSON e.g. string or number.
        Some encoders also support datetime by default.

        Serialization should not be validated, since the developer app would be
        bounced, since the mistake comes from there - use unittests for this!

        """
        value = self._resolve_value(value, environment)

        value = self._serialize(value, environment)

        return value

    def _deserialize(self, value, environment=None):              # pylint: disable=R0201
        """Derserialization worker method."""

        return value

    def deserialize(self, value, environment=None):
        """Deserialize a value into a special application specific format or type.

        `value` can be `Missing`, `None` or something else.

        :param value: the value to be deserialized
        :param environment: additional environment
        """

        value = self._resolve_value(value, environment)

        try:
            value = self._deserialize(value, environment)

            if self._validator is not None:
                value = self._validator(self, value, environment)     # pylint: disable=E1102

        except exc.InvalidValue as ex:
            # just reraise
            raise

        except (exc.Invalid, ValueError, TypeError) as ex:
            # we convert a bare Invalid into InvalidValue
            raise exc.InvalidValue(self, value=value, origin=ex)

        return value
<|endoftext|>


<commit_before>from collections import OrderedDict

from django.core.urlresolvers import reverse_lazy
from django.utils.translation import ugettext_lazy as _

OSCAR_SHOP_NAME = 'Oscar'
OSCAR_SHOP_TAGLINE = ''
OSCAR_HOMEPAGE = reverse_lazy('promotions:home')

# Basket settings
OSCAR_BASKET_COOKIE_LIFETIME = 7 * 24 * 60 * 60
OSCAR_BASKET_COOKIE_OPEN = 'oscar_open_basket'
OSCAR_BASKET_COOKIE_SECURE = False
OSCAR_MAX_BASKET_QUANTITY_THRESHOLD = 10000

# Recently-viewed products
OSCAR_RECENTLY_VIEWED_COOKIE_LIFETIME = 7 * 24 * 60 * 60
OSCAR_RECENTLY_VIEWED_COOKIE_NAME = 'oscar_history'
OSCAR_RECENTLY_VIEWED_COOKIE_SECURE = False
OSCAR_RECENTLY_VIEWED_PRODUCTS = 20

# Currency
OSCAR_DEFAULT_CURRENCY = 'GBP'

# Paths
OSCAR_IMAGE_FOLDER = 'uploads/images/products/%Y/%m/'
OSCAR_PROMOTION_FOLDER = 'uploads/images/promotions/'
OSCAR_DELETE_IMAGE_FILES = True

# Copy this image from oscar/static/img to your MEDIA_ROOT folder.
# It needs to be there so Sorl can resize it.
OSCAR_MISSING_IMAGE_URL = 'static/image_not_found.jpg'
OSCAR_UPLOAD_ROOT = '/tmp'

# Address settings
OSCAR_REQUIRED_ADDRESS_FIELDS = ('first_name', 'last_name', 'line1',
                                 'line4', 'postcode', 'country')

# Pagination settings

OSCAR_OFFERS_PER_PAGE = 20
OSCAR_PRODUCTS_PER_PAGE = 20
OSCAR_REVIEWS_PER_PAGE = 20
OSCAR_NOTIFICATIONS_PER_PAGE = 20
OSCAR_EMAILS_PER_PAGE = 20
OSCAR_ORDERS_PER_PAGE = 20
OSCAR_ADDRESSES_PER_PAGE = 20
OSCAR_STOCK_ALERTS_PER_PAGE = 20
OSCAR_DASHBOARD_ITEMS_PER_PAGE = 20

# Checkout
OSCAR_ALLOW_ANON_CHECKOUT = True

# Promotions
COUNTDOWN, LIST, SINGLE_PRODUCT, TABBED_BLOCK = (
    'Countdown', 'List', 'SingleProduct', 'TabbedBlock')
OSCAR_PROMOTION_MERCHANDISING_BLOCK_TYPES = (
    (COUNTDOWN, "Vertical list"),
    (LIST, "Horizontal list"),
    (TABBED_BLOCK, "Tabbed block"),
    (SINGLE_PRODUCT, "Single product"),
)
OSCAR_PROMOTION_POSITIONS = (('page', 'Page'),
                             ('right', 'Right-hand sidebar'),
                             ('left', 'Left-hand sidebar'))

# Reviews
OSCAR_ALLOW_ANON_REVIEWS = True
OSCAR_MODERATE_REVIEWS = False

# Accounts
OSCAR_ACCOUNTS_REDIRECT_URL = 'customer:profile-view'

# This enables sending alert notifications/emails instantly when products get
# back in stock by listening to stock record update signals.
# This might impact performance for large numbers of stock record updates.
# Alternatively, the management command ``oscar_send_alerts`` can be used to
# run periodically, e.g. as a cron job. In this case eager alerts should be
# disabled.
OSCAR_EAGER_ALERTS = True

# Registration
OSCAR_SEND_REGISTRATION_EMAIL = True
OSCAR_FROM_EMAIL = 'oscar@example.com'

# Slug handling
OSCAR_SLUG_FUNCTION = 'oscar.core.utils.default_slugifier'
OSCAR_SLUG_MAP = {}
OSCAR_SLUG_BLACKLIST = []

# Cookies
OSCAR_COOKIES_DELETE_ON_LOGOUT = ['oscar_recently_viewed_products', ]

# Hidden Oscar features, e.g. wishlists or reviews
OSCAR_HIDDEN_FEATURES = []

# Menu structure of the dashboard navigation
OSCAR_DASHBOARD_NAVIGATION = [
    {
        'label': _('PayPal'),
        'icon': 'icon-globe',
        'children': [
            {
                'label': _('Express transactions'),
                'url_name': 'paypal-express-list',
            },
        ]
    },
    {
        'label': _('Dashboard'),
        'icon': 'icon-th-list',
        'url_name': 'dashboard:index',
    },
    {
        'label': _('Catalogue'),
        'icon': 'icon-sitemap',
        'children': [
            {
                'label': _('Products'),
                'url_name': 'dashboard:catalogue-product-list',
            },
            {
                'label': _('Product Types'),
                'url_name': 'dashboard:catalogue-class-list',
            },
            {
                'label': _('Categories'),
                'url_name': 'dashboard:catalogue-category-list',
            },
            {
                'label': _('Ranges'),
                'url_name': 'dashboard:range-list',
            },
            {
                'label': _('Low stock alerts'),
                'url_name': 'dashboard:stock-alert-list',
            },
        ]
    },
    {
        'label': _('Fulfilment'),
        'icon': 'icon-shopping-cart',
        'children': [
            {
                'label': _('Orders'),
                'url_name': 'dashboard:order-list',
            },
            {
                'label': _('Statistics'),
                'url_name': 'dashboard:order-stats',
            },
            {
                'label': _('Partners'),
                'url_name': 'dashboard:partner-list',
            },
            # The shipping method dashboard is disabled by default as it might
            # be confusing. Weight-based shipping methods aren't hooked into
            # the shipping repository by default (as it would make
            # customising the repository slightly more difficult).
            # {
            #     'label': _('Shipping charges'),
            #     'url_name': 'dashboard:shipping-method-list',
            # },
        ]
    },
    {
        'label': _('Customers'),
        'icon': 'icon-group',
        'children': [
            {
                'label': _('Customers'),
                'url_name': 'dashboard:users-index',
            },
            {
                'label': _('Stock alert requests'),
                'url_name': 'dashboard:user-alert-list',
            },
        ]
    },
    {
        'label': _('Offers'),
        'icon': 'icon-bullhorn',
        'children': [
            {
                'label': _('Offers'),
                'url_name': 'dashboard:offer-list',
            },
            {
                'label': _('Vouchers'),
                'url_name': 'dashboard:voucher-list',
            },
        ],
    },
    {
        'label': _('Content'),
        'icon': 'icon-folder-close',
        'children': [
            {
                'label': _('Content blocks'),
                'url_name': 'dashboard:promotion-list',
            },
            {
                'label': _('Content blocks by page'),
                'url_name': 'dashboard:promotion-list-by-page',
            },
            {
                'label': _('Pages'),
                'url_name': 'dashboard:page-list',
            },
            {
                'label': _('Email templates'),
                'url_name': 'dashboard:comms-list',
            },
            {
                'label': _('Reviews'),
                'url_name': 'dashboard:reviews-list',
            },
        ]
    },
    {
        'label': _('Reports'),
        'icon': 'icon-bar-chart',
        'url_name': 'dashboard:reports-index',
    },
]
OSCAR_DASHBOARD_DEFAULT_ACCESS_FUNCTION = 'oscar.apps.dashboard.nav.default_access_fn'  # noqa

# Search facets
OSCAR_SEARCH_FACETS = {
    'fields': OrderedDict([
        # The key for these dicts will be used when passing facet data
        # to the template. Same for the 'queries' dict below.
        ('product_class', {'name': _('Type'), 'field': 'product_class'}),
        ('rating', {'name': _('Rating'), 'field': 'rating'}),
        # You can specify an 'options' element that will be passed to the
        # SearchQuerySet.facet() call.  It's hard to get 'missing' to work
        # correctly though as of Solr's hilarious syntax for selecting
        # items without a specific facet:
        # http://wiki.apache.org/solr/SimpleFacetParameters#facet.method
        # 'options': {'missing': 'true'}
    ]),
    'queries': OrderedDict([
        ('price_range',
         {
             'name': _('Price range'),
             'field': 'price',
             'queries': [
                 # This is a list of (name, query) tuples where the name will
                 # be displayed on the front-end.
                 (_('0 to 20'), u'[0 TO 20]'),
                 (_('20 to 40'), u'[20 TO 40]'),
                 (_('40 to 60'), u'[40 TO 60]'),
                 (_('60+'), u'[60 TO *]'),
             ]
         }),
    ]),
}

OSCAR_PRODUCT_SEARCH_HANDLER = None

OSCAR_SETTINGS = dict(
    [(k, v) for k, v in locals().items() if k.startswith('OSCAR_')])
<commit_msg>change oscar seting<commit_after>from collections import OrderedDict

from django.core.urlresolvers import reverse_lazy
from django.utils.translation import ugettext_lazy as _

OSCAR_SHOP_NAME = 'Oscar'
OSCAR_SHOP_TAGLINE = ''
OSCAR_HOMEPAGE = reverse_lazy('promotions:home')

# Basket settings
OSCAR_BASKET_COOKIE_LIFETIME = 7 * 24 * 60 * 60
OSCAR_BASKET_COOKIE_OPEN = 'oscar_open_basket'
OSCAR_BASKET_COOKIE_SECURE = False
OSCAR_MAX_BASKET_QUANTITY_THRESHOLD = 10000

# Recently-viewed products
OSCAR_RECENTLY_VIEWED_COOKIE_LIFETIME = 7 * 24 * 60 * 60
OSCAR_RECENTLY_VIEWED_COOKIE_NAME = 'oscar_history'
OSCAR_RECENTLY_VIEWED_COOKIE_SECURE = False
OSCAR_RECENTLY_VIEWED_PRODUCTS = 20

# Currency
OSCAR_DEFAULT_CURRENCY = 'GBP'

# Paths
OSCAR_IMAGE_FOLDER = 'images/products/%Y/%m/'
OSCAR_PROMOTION_FOLDER = 'images/promotions/'
OSCAR_DELETE_IMAGE_FILES = True

# Copy this image from oscar/static/img to your MEDIA_ROOT folder.
# It needs to be there so Sorl can resize it.
OSCAR_MISSING_IMAGE_URL = 'static/image_not_found.jpg'
OSCAR_UPLOAD_ROOT = '/tmp'

# Address settings
OSCAR_REQUIRED_ADDRESS_FIELDS = ('first_name', 'last_name', 'line1',
                                 'line4', 'postcode', 'country')

# Pagination settings

OSCAR_OFFERS_PER_PAGE = 20
OSCAR_PRODUCTS_PER_PAGE = 20
OSCAR_REVIEWS_PER_PAGE = 20
OSCAR_NOTIFICATIONS_PER_PAGE = 20
OSCAR_EMAILS_PER_PAGE = 20
OSCAR_ORDERS_PER_PAGE = 20
OSCAR_ADDRESSES_PER_PAGE = 20
OSCAR_STOCK_ALERTS_PER_PAGE = 20
OSCAR_DASHBOARD_ITEMS_PER_PAGE = 20

# Checkout
OSCAR_ALLOW_ANON_CHECKOUT = True

# Promotions
COUNTDOWN, LIST, SINGLE_PRODUCT, TABBED_BLOCK = (
    'Countdown', 'List', 'SingleProduct', 'TabbedBlock')
OSCAR_PROMOTION_MERCHANDISING_BLOCK_TYPES = (
    (COUNTDOWN, "Vertical list"),
    (LIST, "Horizontal list"),
    (TABBED_BLOCK, "Tabbed block"),
    (SINGLE_PRODUCT, "Single product"),
)
OSCAR_PROMOTION_POSITIONS = (('page', 'Page'),
                             ('right', 'Right-hand sidebar'),
                             ('left', 'Left-hand sidebar'))

# Reviews
OSCAR_ALLOW_ANON_REVIEWS = True
OSCAR_MODERATE_REVIEWS = False

# Accounts
OSCAR_ACCOUNTS_REDIRECT_URL = 'customer:profile-view'

# This enables sending alert notifications/emails instantly when products get
# back in stock by listening to stock record update signals.
# This might impact performance for large numbers of stock record updates.
# Alternatively, the management command ``oscar_send_alerts`` can be used to
# run periodically, e.g. as a cron job. In this case eager alerts should be
# disabled.
OSCAR_EAGER_ALERTS = True

# Registration
OSCAR_SEND_REGISTRATION_EMAIL = True
OSCAR_FROM_EMAIL = 'oscar@example.com'

# Slug handling
OSCAR_SLUG_FUNCTION = 'oscar.core.utils.default_slugifier'
OSCAR_SLUG_MAP = {}
OSCAR_SLUG_BLACKLIST = []

# Cookies
OSCAR_COOKIES_DELETE_ON_LOGOUT = ['oscar_recently_viewed_products', ]

# Hidden Oscar features, e.g. wishlists or reviews
OSCAR_HIDDEN_FEATURES = []

# Menu structure of the dashboard navigation
OSCAR_DASHBOARD_NAVIGATION = [
    {
        'label': _('PayPal'),
        'icon': 'icon-globe',
        'children': [
            {
                'label': _('Express transactions'),
                'url_name': 'paypal-express-list',
            },
        ]
    },
    {
        'label': _('Dashboard'),
        'icon': 'icon-th-list',
        'url_name': 'dashboard:index',
    },
    {
        'label': _('Catalogue'),
        'icon': 'icon-sitemap',
        'children': [
            {
                'label': _('Products'),
                'url_name': 'dashboard:catalogue-product-list',
            },
            {
                'label': _('Product Types'),
                'url_name': 'dashboard:catalogue-class-list',
            },
            {
                'label': _('Categories'),
                'url_name': 'dashboard:catalogue-category-list',
            },
            {
                'label': _('Ranges'),
                'url_name': 'dashboard:range-list',
            },
            {
                'label': _('Low stock alerts'),
                'url_name': 'dashboard:stock-alert-list',
            },
        ]
    },
    {
        'label': _('Fulfilment'),
        'icon': 'icon-shopping-cart',
        'children': [
            {
                'label': _('Orders'),
                'url_name': 'dashboard:order-list',
            },
            {
                'label': _('Statistics'),
                'url_name': 'dashboard:order-stats',
            },
            {
                'label': _('Partners'),
                'url_name': 'dashboard:partner-list',
            },
            # The shipping method dashboard is disabled by default as it might
            # be confusing. Weight-based shipping methods aren't hooked into
            # the shipping repository by default (as it would make
            # customising the repository slightly more difficult).
            # {
            #     'label': _('Shipping charges'),
            #     'url_name': 'dashboard:shipping-method-list',
            # },
        ]
    },
    {
        'label': _('Customers'),
        'icon': 'icon-group',
        'children': [
            {
                'label': _('Customers'),
                'url_name': 'dashboard:users-index',
            },
            {
                'label': _('Stock alert requests'),
                'url_name': 'dashboard:user-alert-list',
            },
        ]
    },
    {
        'label': _('Offers'),
        'icon': 'icon-bullhorn',
        'children': [
            {
                'label': _('Offers'),
                'url_name': 'dashboard:offer-list',
            },
            {
                'label': _('Vouchers'),
                'url_name': 'dashboard:voucher-list',
            },
        ],
    },
    {
        'label': _('Content'),
        'icon': 'icon-folder-close',
        'children': [
            {
                'label': _('Content blocks'),
                'url_name': 'dashboard:promotion-list',
            },
            {
                'label': _('Content blocks by page'),
                'url_name': 'dashboard:promotion-list-by-page',
            },
            {
                'label': _('Pages'),
                'url_name': 'dashboard:page-list',
            },
            {
                'label': _('Email templates'),
                'url_name': 'dashboard:comms-list',
            },
            {
                'label': _('Reviews'),
                'url_name': 'dashboard:reviews-list',
            },
        ]
    },
    {
        'label': _('Reports'),
        'icon': 'icon-bar-chart',
        'url_name': 'dashboard:reports-index',
    },
]
OSCAR_DASHBOARD_DEFAULT_ACCESS_FUNCTION = 'oscar.apps.dashboard.nav.default_access_fn'  # noqa

# Search facets
OSCAR_SEARCH_FACETS = {
    'fields': OrderedDict([
        # The key for these dicts will be used when passing facet data
        # to the template. Same for the 'queries' dict below.
        ('product_class', {'name': _('Type'), 'field': 'product_class'}),
        ('rating', {'name': _('Rating'), 'field': 'rating'}),
        # You can specify an 'options' element that will be passed to the
        # SearchQuerySet.facet() call.  It's hard to get 'missing' to work
        # correctly though as of Solr's hilarious syntax for selecting
        # items without a specific facet:
        # http://wiki.apache.org/solr/SimpleFacetParameters#facet.method
        # 'options': {'missing': 'true'}
    ]),
    'queries': OrderedDict([
        ('price_range',
         {
             'name': _('Price range'),
             'field': 'price',
             'queries': [
                 # This is a list of (name, query) tuples where the name will
                 # be displayed on the front-end.
                 (_('0 to 20'), u'[0 TO 20]'),
                 (_('20 to 40'), u'[20 TO 40]'),
                 (_('40 to 60'), u'[40 TO 60]'),
                 (_('60+'), u'[60 TO *]'),
             ]
         }),
    ]),
}

OSCAR_PRODUCT_SEARCH_HANDLER = None

OSCAR_SETTINGS = dict(
    [(k, v) for k, v in locals().items() if k.startswith('OSCAR_')])
<|endoftext|>