<commit_before># No shebang line, this module is meant to be imported
#
# INITIAL: June 19 2011
# PURPOSE: To find, parse, and return a logger configuration
#
# This file is part of PyFarm.
# Copyright (C) 2008-2011 Oliver Palmer
#
# PyFarm is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# PyFarm 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with PyFarm.  If not, see <http://www.gnu.org/licenses/>.

import os
import re
import sys
import types
import xml.etree.ElementTree
import ConfigParser

import ltypes

# root directory setup
cwd = os.path.dirname(os.path.abspath(__file__))
CFG = os.path.join(cwd, "cfg")

# config files
CFG_LEVELS = os.path.join(CFG, "levels.xml")
INI_FORMAT = os.path.join(CFG, "format.ini")
INI_GLOBALS = os.path.join(CFG, "globals.ini")

def getIniDict(config):
    '''Return a dictionary from an ini file'''
    data = {}
    parse = ConfigParser.ConfigParser()
    parse.read(config)

    # retrieve all sections
    for section in parse.sections():
        data[section] = {}

        for key, value in parse.items(section):
            # convert string -> float
            if value.isdigit() and "." in value:
                value = float(value)

            # convert string -> int
            if value.isdigit() and "." not in value:
                value = int(value)

            # convert string -> True
            if value == "True":
                value = True

            # convert string -> False
            if value == "False":
                value = False

            # add value to data
            data[section][key] = value

    return data

def build(config):
    '''
    Given a dictionary ensure the required data
    exists and is properly populated
    '''
    # add enabled if it does not already exist
    if not config.has_key('enabled'):
        config['enabled'] = True

    # ensure we have an output stream
    if not config.has_key('stream'):
        config['stream'] = 'sys.stdout'
    config['stream'] = eval(config['stream'])

    # breakdown color if it was given
    if not config.has_key('color'):
        config['color'] = ""
    config['color'] = config['color'].split(";")

def getXml(xmlPath, root):
    '''Parse an xml file and return a list of elements matching root'''
    tree = xml.etree.ElementTree.parse(xmlPath)

    # return all elements with tags that match root
    return [entry for entry in tree.findall(root) if entry.tag == root]

def getFormat():
    '''Return format information from the config'''
    data = {}
    parse = ConfigParser.ConfigParser()
    parse.read(INI_GLOBALS)

    return data

class Levels(object):
    RequiredKeys = ["name"]
    PopulateKeys = {"function" : "name"}

    def __init__(self, config):
        self.config = getXml(config, "level")
        self.data = self.__data()

    def __data(self):
        '''Read and return information from the xml file'''
        levels = []

        for attrib in [ entry.attrib for entry in self.config ]:
            self.__checkKeys(attrib)
            self.__populateKeys(attrib)
            self.__validateFunction(attrib)
            levels.append(attrib)

        return levels

    def __checkKeys(self, data):
        '''
        Check and ensure that all keys in Levels.RequiredKeys exist and are
        present in data
        '''
        for key in Levels.RequiredKeys:
            if not data.has_key(key):
                raise KeyError("missing required key: %s" % key)

    def __populateKeys(self, data):
        '''
        Given the key/value pairs in Levels.PopulateKeys ensure that each key
        exists in data and if not populate it from value.  If value itself is a
        string we use that to perform a lookup in data, otherwise we simply set
        the value of data[key] to be equal to the value from Levels.PopulateKeys
        '''
        for key, value in Levels.PopulateKeys.items():
            if not data.has_key(key):
                if type(value) == types.StringType:
                    data[key] = data[value]
                else:
                    data[key] = value

    def __validateFunction(self, data):
        '''
        Ensure that all function names in data are valid (no spaces, periods,
        or other characters that are not allowed in function names
        '''
        function = data.get("function")

        # ensure the function name is a string
        if not type(function) == types.StringType:
            raise TypeError("Invalid type for function, was expecting a string")

        # ensure that we have only ascii characters/numbers in the
        # function name
        if re.search("\W", function):
            msg = "level contains non-alpha characters: %s" % function
            raise SyntaxError(function)

class ReadConfig(object):
    '''Read and return a configuration'''
    def __init__(self):
        self.colors = {}
        self.levels = self.__levels()
        self.globals = self.__globals()

    def __levels(self):
        '''Get the level configuration'''
        levels = Levels(CFG_LEVELS)
        return levels.data

    def __globals(self):
        '''Find and parse all settings from the global config'''
        config = {}
        parse = ConfigParser.ConfigParser()
        parse.read(INI_GLOBALS)

        s = "LoggerGlobals"
        data = {
            "LEVEL" : lambda option: parse.getint(s, option),
            "ALLOW_TRACE" : lambda option: parse.getboolean(s, option),
            "WARN_MISSING_LEVEL" : lambda option: parse.getboolean(s, option),
            "DEFAULT_STREAM" : lambda option: eval(parse.get(s, option))
        }

        for option in parse.options("LoggerGlobals"):
            optionKey = option.upper()
            config[optionKey] = data[optionKey](option)

        return ltypes.AttrDict(config)

class Format(object):
    '''Parse and configure formatting information'''
    def __init__(self):
        self.config = getIniDict(INI_FORMAT)

        # level name setup
        level = self.config['LevelName']
        self.LEVEL_PRE_STR = level['pre_string']
        self.LEVEL_POST_STR = level['post_string']
        self.LEVEL_PRE_SEP = level['pre_sep']
        self.LEVEL_POST_SEP = level['post_sep']

if __name__ == '__main__':
    print "WARNING: config testing"
    f = Format()
    print f.LEVEL_POST_SEP, f.LEVEL_POST_STR<commit_msg>Added support for multiline configs, pre-resolving some variables<commit_after># No shebang line, this module is meant to be imported
#
# INITIAL: June 19 2011
# PURPOSE: To find, parse, and return a logger configuration
#
# This file is part of PyFarm.
# Copyright (C) 2008-2011 Oliver Palmer
#
# PyFarm is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# PyFarm 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with PyFarm.  If not, see <http://www.gnu.org/licenses/>.

import os
import re
import sys
import types
import xml.etree.ElementTree
import ConfigParser

import ltypes

# root directory setup
cwd = os.path.dirname(os.path.abspath(__file__))
CFG = os.path.join(cwd, "cfg")

# config files
CFG_LEVELS = os.path.join(CFG, "levels.xml")
INI_FORMAT = os.path.join(CFG, "format.ini")
INI_GLOBALS = os.path.join(CFG, "globals.ini")

def getIniDict(config):
    '''Return a dictionary from an ini file'''
    data = {}
    parse = ConfigParser.ConfigParser()
    parse.read(config)

    # retrieve all sections
    for section in parse.sections():
        data[section] = {}

        for key, value in parse.items(section):
            # replace all newlines
            value = value.replace("\n", "")

            # convert string -> float
            if value.isdigit() and "." in value:
                value = float(value)

            # convert string -> int
            if value.isdigit() and "." not in value:
                value = int(value)

            # convert string -> True
            if value == "True":
                value = True

            # convert string -> False
            if value == "False":
                value = False

            # add value to data
            data[section][key] = value

    return data

def build(config):
    '''
    Given a dictionary ensure the required data
    exists and is properly populated
    '''
    # add enabled if it does not already exist
    if not config.has_key('enabled'):
        config['enabled'] = True

    # ensure we have an output stream
    if not config.has_key('stream'):
        config['stream'] = 'sys.stdout'
    config['stream'] = eval(config['stream'])

    # breakdown color if it was given
    if not config.has_key('color'):
        config['color'] = ""
    config['color'] = config['color'].split(";")

def getXml(xmlPath, root):
    '''Parse an xml file and return a list of elements matching root'''
    tree = xml.etree.ElementTree.parse(xmlPath)

    # return all elements with tags that match root
    return [entry for entry in tree.findall(root) if entry.tag == root]

def getFormat():
    '''Return format information from the config'''
    data = {}
    parse = ConfigParser.ConfigParser()
    parse.read(INI_GLOBALS)

    return data

class Levels(object):
    RequiredKeys = ["name"]
    PopulateKeys = {"function" : "name"}

    def __init__(self, config):
        self.config = getXml(config, "level")
        self.data = self.__data()

    def __data(self):
        '''Read and return information from the xml file'''
        levels = []

        for attrib in [ entry.attrib for entry in self.config ]:
            self.__checkKeys(attrib)
            self.__populateKeys(attrib)
            self.__validateFunction(attrib)
            levels.append(attrib)

        return levels

    def __checkKeys(self, data):
        '''
        Check and ensure that all keys in Levels.RequiredKeys exist and are
        present in data
        '''
        for key in Levels.RequiredKeys:
            if not data.has_key(key):
                raise KeyError("missing required key: %s" % key)

    def __populateKeys(self, data):
        '''
        Given the key/value pairs in Levels.PopulateKeys ensure that each key
        exists in data and if not populate it from value.  If value itself is a
        string we use that to perform a lookup in data, otherwise we simply set
        the value of data[key] to be equal to the value from Levels.PopulateKeys
        '''
        for key, value in Levels.PopulateKeys.items():
            if not data.has_key(key):
                if type(value) == types.StringType:
                    data[key] = data[value]
                else:
                    data[key] = value

    def __validateFunction(self, data):
        '''
        Ensure that all function names in data are valid (no spaces, periods,
        or other characters that are not allowed in function names
        '''
        function = data.get("function")

        # ensure the function name is a string
        if not type(function) == types.StringType:
            raise TypeError("Invalid type for function, was expecting a string")

        # ensure that we have only ascii characters/numbers in the
        # function name
        if re.search("\W", function):
            msg = "level contains non-alpha characters: %s" % function
            raise SyntaxError(function)

class ReadConfig(object):
    '''Read and return a configuration'''
    def __init__(self):
        self.colors = {}
        self.levels = self.__levels()
        self.globals = self.__globals()

    def __levels(self):
        '''Get the level configuration'''
        levels = Levels(CFG_LEVELS)
        return levels.data

    def __globals(self):
        '''Find and parse all settings from the global config'''
        config = {}
        parse = ConfigParser.ConfigParser()
        parse.read(INI_GLOBALS)

        s = "LoggerGlobals"
        data = {
            "LEVEL" : lambda option: parse.getint(s, option),
            "ALLOW_TRACE" : lambda option: parse.getboolean(s, option),
            "WARN_MISSING_LEVEL" : lambda option: parse.getboolean(s, option),
            "DEFAULT_STREAM" : lambda option: eval(parse.get(s, option))
        }

        for option in parse.options("LoggerGlobals"):
            optionKey = option.upper()
            config[optionKey] = data[optionKey](option)

        return ltypes.AttrDict(config)

def getFormat():
    '''
    Retrieve the default data from the ini file and resolve as much
    data as much data as possible to save on processing
    '''
    config = getIniDict(INI_FORMAT)

    for section, data in config.items():
        for key, value in data.items():
            # replace any numerical values with blank space
            if type(value) == types.IntType:
                config[section][key] = " "*value

    return config

FORMAT_DATA = getFormat()

if __name__ == '__main__':
    print "WARNING: config testing"
    import pprint
    pprint.pprint(FORMAT_DATA)<|endoftext|>


<commit_before># -*- coding: utf-8 -*-
from odoo import http, _
from odoo.exceptions import AccessError
from odoo.http import request

from odoo.addons.website_portal.controllers.main import website_account
from odoo.addons.website_event.controllers.main import WebsiteEventController
from odoo.addons.website_sale.controllers.main import WebsiteSale
from odoo.addons.website.models.website import slug

class PortalEvent(website_account, WebsiteEventController, WebsiteSale):

    def _tickets_domain(self, partner=None):
        partner = partner or request.env.user.partner_id
        return [
            ('attendee_partner_id', '=', partner.id),
        ]

    @http.route()
    def account(self, **kw):
        """ Add sales documents to main account page """
        response = super(PortalEvent, self).account(**kw)

        domain = self._tickets_domain()
        tickets_count = request.env['event.registration'].search_count(domain)

        response.qcontext.update({
            'tickets_count': tickets_count,
        })
        return response

    @http.route(['/my/tickets', '/my/tickets/page/<int:page>'], type='http', auth="user", website=True)
    def portal_my_tickets(self, page=1, date_begin=None, date_end=None, **kw):
        values = self._prepare_portal_layout_values()
        Registration = request.env['event.registration']

        domain = self._tickets_domain()
        archive_groups = self._get_archive_groups('event.registration', domain)
        if date_begin and date_end:
            domain += [('create_date', '>', date_begin), ('create_date', '<=', date_end)]

        # count for pager
        ticket_count = Registration.search_count(domain)
        # make pager
        pager = request.website.pager(
            url="/my/tickets",
            url_args={'date_begin': date_begin, 'date_end': date_end},
            total=ticket_count,
            page=page,
            step=self._items_per_page
        )
        # search the count to display, according to the pager data
        tickets = Registration.search(domain, limit=self._items_per_page, offset=pager['offset'])

        values.update({
            'date': date_begin,
            'tickets': tickets,
            'pager': pager,
            'archive_groups': archive_groups,
            'default_url': '/my/tickets',
        })
        return request.render("portal_event.portal_my_tickets", values)

    def _has_ticket_access(self, ticket, to_update=False):

        if not ticket.exists():
            return False

        try:
            ticket.check_access_rights('read')
            ticket.check_access_rule('read')
        except AccessError:
            return False

        if ticket.attendee_partner_id.id == request.env.user.partner_id.id:
            return True

        if to_update:
            # not an attendee, so cannot update
            return False

        return request.env.user.has_group('event.group_event_manager')

    @http.route(['/my/tickets/<int:ticket>'], type='http', auth="user", website=True)
    def ticket_page(self, ticket=None, **kw):
        values = self._prepare_portal_layout_values()
        ticket = request.env['event.registration'].browse([ticket])
        if not ticket or not ticket.exists():
            return request.render("website.404")

        if not self._has_ticket_access(ticket):
            return request.render("website.403")

        ticket_sudo = ticket.sudo()

        values.update({
            'ticket': ticket_sudo,
        })
        return request.render("portal_event.portal_ticket_page", values)

    @http.route(['/my/tickets/transfer'], type='http', auth="user", methods=['GET'], website=True)
    def ticket_transfer_editor(self, **kw):
        """Special controller to customize result messages"""
        if not request.env.user.has_group('website.group_website_designer'):
            return request.render("website.403")

        values = self._prepare_portal_layout_values()
        values.update({
            'editor_mode': True,
            'error': kw.get('error')
        })
        return request.render("portal_event.portal_ticket_transfer", values)

    @http.route(['/my/tickets/transfer'], type='http', auth="user", methods=['POST'], website=True)
    def ticket_transfer(self, to_email, ticket_id, **kw):
        values = self._prepare_portal_layout_values()
        ticket = request.env['event.registration'].browse([int(ticket_id)])
        ticket.ensure_one()

        if not self._has_ticket_access(ticket, to_update=True):
            return request.render("website.403")

        error = None

        # Yes, error is None here but let's have correct indent for possible adding conditions.
        if not error:
            receiver = request.env['res.partner'].sudo().search([
                ('email', '=ilike', to_email)
            ], limit=1)

        if not receiver:
            error = 'receiver_not_found'

        if not error:
            domain = [('attendee_partner_id', '=', receiver.id),
                      ('state', 'not in', ['cancel']),
                      ('event_id', '=', ticket.event_id.id)]
            if request.env['event.registration'].search_count(domain):
                error = 'receiver_has_ticket'

        if not error:
            # do the transfer
            ticket.sudo().transferring_started(receiver)

        values.update({
            'to_email': to_email,
            'error': error,
        })
        return request.render("portal_event.portal_ticket_transfer", values)

    @http.route(['/my/tickets/transfer/receive'], type='http', auth="user", methods=['GET', 'POST'], website=True)
    def ticket_transfer_receive(self, transfer_ticket, **kw):
        ticket = transfer_ticket
        ticket = request.env['event.registration'].browse([int(ticket)])
        ticket.ensure_one()

        if not self._has_ticket_access(ticket, to_update=True):
            return request.render("website.403")

        values = self._prepare_portal_layout_values()
        if request.httprequest.method == 'GET':
            tickets = self._process_tickets_details({'nb_register-0': 1})
            values.update({
                'transfer_ticket': ticket,
                'tickets': tickets,
                'event': ticket.event_id,
            })
            return request.env['ir.ui.view'].render_template(
                "portal_event.portal_ticket_transfer_receive", values)

        # handle filled form

        receiver = ticket.attendee_partner_id
        registration = self._process_registration_details(kw)[0]
        registration['event_id'] = ticket.event_id.id
        partner_vals = request.env['event.registration']._prepare_partner(registration)
        assert not partner_vals.get('email')

        receiver.sudo().write(partner_vals)

        ticket.sudo().transferring_finished()
        return request.redirect('/my/tickets')

    @http.route(['/my/tickets/change'], type='http', auth="user", methods=['POST'], website=True)
    def ticket_change(self, ticket_id, **kw):
        ticket = request.env['event.registration'].browse([int(ticket_id)])

        if not self._has_ticket_access(ticket, to_update=True):
            return request.render("website.403")

        ticket = ticket.sudo()
        line = ticket.sale_order_line_id
        assert line
        product = line.product_id
        refund_price = line.price_subtotal

        order = request.website.sale_get_order(force_create=True)
        name = _('Ticket change: %s') % product.name
        order.add_refund_line(line, name)

        # TODO: make redirection customizable
        return request.redirect("/event/%s/register" % slug(ticket.event_id))

    @http.route()
    def cart(self, **post):
        response = super(PortalEvent, self).cart(**post)
        if post.get('total_is_negative'):
            response.qcontext.update({
                'warning_msg': _('Total amount is negative. Please add more tickets or products'),
            })
        return response
<commit_msg>[IMP] My Tickets: show only confirmed tickets<commit_after># -*- coding: utf-8 -*-
from odoo import http, _
from odoo.exceptions import AccessError
from odoo.http import request

from odoo.addons.website_portal.controllers.main import website_account
from odoo.addons.website_event.controllers.main import WebsiteEventController
from odoo.addons.website_sale.controllers.main import WebsiteSale
from odoo.addons.website.models.website import slug

class PortalEvent(website_account, WebsiteEventController, WebsiteSale):

    def _tickets_domain(self, partner=None):
        partner = partner or request.env.user.partner_id
        return [
            ('attendee_partner_id', '=', partner.id),
            ('state', '=', 'open'),
        ]

    @http.route()
    def account(self, **kw):
        """ Add sales documents to main account page """
        response = super(PortalEvent, self).account(**kw)

        domain = self._tickets_domain()
        tickets_count = request.env['event.registration'].search_count(domain)

        response.qcontext.update({
            'tickets_count': tickets_count,
        })
        return response

    @http.route(['/my/tickets', '/my/tickets/page/<int:page>'], type='http', auth="user", website=True)
    def portal_my_tickets(self, page=1, date_begin=None, date_end=None, **kw):
        values = self._prepare_portal_layout_values()
        Registration = request.env['event.registration']

        domain = self._tickets_domain()
        archive_groups = self._get_archive_groups('event.registration', domain)
        if date_begin and date_end:
            domain += [('create_date', '>', date_begin), ('create_date', '<=', date_end)]

        # count for pager
        ticket_count = Registration.search_count(domain)
        # make pager
        pager = request.website.pager(
            url="/my/tickets",
            url_args={'date_begin': date_begin, 'date_end': date_end},
            total=ticket_count,
            page=page,
            step=self._items_per_page
        )
        # search the count to display, according to the pager data
        tickets = Registration.search(domain, limit=self._items_per_page, offset=pager['offset'])

        values.update({
            'date': date_begin,
            'tickets': tickets,
            'pager': pager,
            'archive_groups': archive_groups,
            'default_url': '/my/tickets',
        })
        return request.render("portal_event.portal_my_tickets", values)

    def _has_ticket_access(self, ticket, to_update=False):

        if not ticket.exists():
            return False

        try:
            ticket.check_access_rights('read')
            ticket.check_access_rule('read')
        except AccessError:
            return False

        if ticket.attendee_partner_id.id == request.env.user.partner_id.id:
            return True

        if to_update:
            # not an attendee, so cannot update
            return False

        return request.env.user.has_group('event.group_event_manager')

    @http.route(['/my/tickets/<int:ticket>'], type='http', auth="user", website=True)
    def ticket_page(self, ticket=None, **kw):
        values = self._prepare_portal_layout_values()
        ticket = request.env['event.registration'].browse([ticket])
        if not ticket or not ticket.exists():
            return request.render("website.404")

        if not self._has_ticket_access(ticket):
            return request.render("website.403")

        ticket_sudo = ticket.sudo()

        values.update({
            'ticket': ticket_sudo,
        })
        return request.render("portal_event.portal_ticket_page", values)

    @http.route(['/my/tickets/transfer'], type='http', auth="user", methods=['GET'], website=True)
    def ticket_transfer_editor(self, **kw):
        """Special controller to customize result messages"""
        if not request.env.user.has_group('website.group_website_designer'):
            return request.render("website.403")

        values = self._prepare_portal_layout_values()
        values.update({
            'editor_mode': True,
            'error': kw.get('error')
        })
        return request.render("portal_event.portal_ticket_transfer", values)

    @http.route(['/my/tickets/transfer'], type='http', auth="user", methods=['POST'], website=True)
    def ticket_transfer(self, to_email, ticket_id, **kw):
        values = self._prepare_portal_layout_values()
        ticket = request.env['event.registration'].browse([int(ticket_id)])
        ticket.ensure_one()

        if not self._has_ticket_access(ticket, to_update=True):
            return request.render("website.403")

        error = None

        # Yes, error is None here but let's have correct indent for possible adding conditions.
        if not error:
            receiver = request.env['res.partner'].sudo().search([
                ('email', '=ilike', to_email)
            ], limit=1)

        if not receiver:
            error = 'receiver_not_found'

        if not error:
            domain = [('attendee_partner_id', '=', receiver.id),
                      ('state', 'not in', ['cancel']),
                      ('event_id', '=', ticket.event_id.id)]
            if request.env['event.registration'].search_count(domain):
                error = 'receiver_has_ticket'

        if not error:
            # do the transfer
            ticket.sudo().transferring_started(receiver)

        values.update({
            'to_email': to_email,
            'error': error,
        })
        return request.render("portal_event.portal_ticket_transfer", values)

    @http.route(['/my/tickets/transfer/receive'], type='http', auth="user", methods=['GET', 'POST'], website=True)
    def ticket_transfer_receive(self, transfer_ticket, **kw):
        ticket = transfer_ticket
        ticket = request.env['event.registration'].browse([int(ticket)])
        ticket.ensure_one()

        if not self._has_ticket_access(ticket, to_update=True):
            return request.render("website.403")

        values = self._prepare_portal_layout_values()
        if request.httprequest.method == 'GET':
            tickets = self._process_tickets_details({'nb_register-0': 1})
            values.update({
                'transfer_ticket': ticket,
                'tickets': tickets,
                'event': ticket.event_id,
            })
            return request.env['ir.ui.view'].render_template(
                "portal_event.portal_ticket_transfer_receive", values)

        # handle filled form

        receiver = ticket.attendee_partner_id
        registration = self._process_registration_details(kw)[0]
        registration['event_id'] = ticket.event_id.id
        partner_vals = request.env['event.registration']._prepare_partner(registration)
        assert not partner_vals.get('email')

        receiver.sudo().write(partner_vals)

        ticket.sudo().transferring_finished()
        return request.redirect('/my/tickets')

    @http.route(['/my/tickets/change'], type='http', auth="user", methods=['POST'], website=True)
    def ticket_change(self, ticket_id, **kw):
        ticket = request.env['event.registration'].browse([int(ticket_id)])

        if not self._has_ticket_access(ticket, to_update=True):
            return request.render("website.403")

        ticket = ticket.sudo()
        line = ticket.sale_order_line_id
        assert line
        product = line.product_id
        refund_price = line.price_subtotal

        order = request.website.sale_get_order(force_create=True)
        name = _('Ticket change: %s') % product.name
        order.add_refund_line(line, name)

        # TODO: make redirection customizable
        return request.redirect("/event/%s/register" % slug(ticket.event_id))

    @http.route()
    def cart(self, **post):
        response = super(PortalEvent, self).cart(**post)
        if post.get('total_is_negative'):
            response.qcontext.update({
                'warning_msg': _('Total amount is negative. Please add more tickets or products'),
            })
        return response
<|endoftext|>


<commit_before>import logging
import cffi
import cle

from sortedcontainers import SortedDict

from ..analysis import Analysis

_l = logging.getLogger(name=__name__)

class CFBlanketView:
    """
    A view into the control-flow blanket.
    """
    def __init__(self, cfb):
        self._cfb = cfb

    def __getitem__(self, item):

        if isinstance(item, slice):
            addr = item.start
            start_addr = self._cfb.floor_addr(addr)

            addr_ = start_addr
            while True:
                obj = self._cfb[addr_]
                yield obj

                addr_ += obj
                # Find gaps
                # TODO: finish it
                raise NotImplementedError()

#
# Memory region
#

class MemoryRegion:
    def __init__(self, addr, size, type_, object_, cle_region):
        self.addr = addr
        self.size = size
        self.type = type_
        self.object = object_
        self.cle_region = cle_region

#
# An address can be mapped to one of the following types of object
# - Block
# - MemoryData
# - Unknown
#

class Unknown:
    def __init__(self, addr, size, bytes_=None, object_=None, segment=None, section=None):
        self.addr = addr
        self.size = size

        # Optional
        self.bytes = bytes_
        self.object = object_
        self.segment = segment
        self.section = section

        if size == 0:
            raise Exception("You cannot create an unknown region of size 0.")

    def __repr__(self):
        s = "<Unknown %#x-%#x>" % (self.addr, self.addr + self.size)
        return s

class CFBlanket(Analysis):
    """
    A Control-Flow Blanket is a representation for storing all instructions, data entries, and bytes of a full program.
    """
    def __init__(self, cfg=None):
        self._blanket = SortedDict()

        self._ffi = cffi.FFI()
        self._regions = [ ]

        self._init_regions()

        if cfg is not None:
            self._from_cfg(cfg)
        else:
            _l.debug("CFG is not specified. Initialize CFBlanket from the knowledge base.")
            for func in self.kb.functions.values():
                self.add_function(func)

    def _init_regions(self):

        for obj in self.project.loader.all_objects:
            if isinstance(obj, cle.MetaELF):
                if obj.sections:
                    # Enumerate sections in an ELF file
                    for section in obj.sections:
                        mr = MemoryRegion(section.vaddr, section.memsize, 'TODO', obj, section)
                        self._regions.append(mr)
                else:
                    raise NotImplementedError()
            else:
                mr = MemoryRegion(obj.min_addr, obj.size if hasattr(obj, 'size') else 80, 'TODO', obj, None)
                self._regions.append(mr)

        # Sort them just in case
        self._regions = list(sorted(self._regions, key=lambda x: x.addr))

    @property
    def regions(self):
        """
        Return all memory regions.
        """

        return self._regions

    def floor_addr(self, addr):
        try:
            return next(self._blanket.irange(maximum=addr, reverse=True))
        except StopIteration:
            raise KeyError(addr)

    def floor_item(self, addr):
        key = self.floor_addr(addr)
        return key, self._blanket[key]

    def floor_items(self, addr=None, reverse=False):
        if addr is None:
            start_addr = None
        else:
            try:
                start_addr = next(self._blanket.irange(maximum=addr, reverse=True))
            except StopIteration:
                start_addr = addr

        for key in self._blanket.irange(minimum=start_addr, reverse=reverse):
            yield key, self._blanket[key]

    def ceiling_addr(self, addr):
        try:
            return next(self._blanket.irange(minimum=addr))
        except StopIteration:
            raise KeyError(addr)

    def ceiling_item(self, addr):
        key = self.ceiling_addr(addr)
        return key, self._blanket[key]

    def ceiling_items(self, addr=None, reverse=False, include_first=True):
        if addr is None:
            start_addr = None
        else:
            try:
                start_addr = next(self._blanket.irange(minimum=addr))
            except StopIteration:
                start_addr = addr

        for key in self._blanket.irange(maximum=start_addr if include_first else start_addr - 1, reverse=reverse):
            yield key, self._blanket[key]

    def __getitem__(self, addr):
        return self._blanket[addr]

    def add_obj(self, addr, obj):
        """
        Adds an object `obj` to the blanket at the specified address `addr`
        """
        self._blanket[addr] = obj

    def add_function(self, func):
        """
        Add a function `func` and all blocks of this function to the blanket.
        """
        for block in func.blocks:
            self.add_obj(block.addr, block)

    def dbg_repr(self):
        """
        The debugging representation of this CFBlanket.

        :return:    The debugging representation of this CFBlanket.
        :rtype:     str
        """

        output = [ ]

        for obj in self.project.loader.all_objects:
            for section in obj.sections:
                if section.memsize == 0:
                    continue
                min_addr, max_addr = section.min_addr, section.max_addr
                output.append("### Object %s" % repr(section))
                output.append("### Range %#x-%#x" % (min_addr, max_addr))

                pos = min_addr
                while pos < max_addr:
                    try:
                        addr, thing = self.floor_item(pos)
                        output.append("%#x: %s" % (addr, repr(thing)))

                        if thing.size == 0: pos += 1
                        else: pos += thing.size
                    except KeyError:
                        pos += 1

                output.append("")

        return "\n".join(output)

    def _from_cfg(self, cfg):
        """
        Initialize CFBlanket from a CFG instance.

        :param cfg: A CFG instance.
        :return:    None
        """

        # Let's first add all functions first
        for func in cfg.kb.functions.values():
            self.add_function(func)

        self._mark_unknowns()

    def _mark_unknowns(self):
        """
        Mark all unmapped regions.

        :return: None
        """

        for obj in self.project.loader.all_objects:
            if isinstance(obj, cle.ELF):
                # sections?
                if obj.sections:
                    for section in obj.sections:
                        if not section.memsize or not section.vaddr:
                            continue
                        min_addr, max_addr = section.min_addr, section.max_addr
                        self._mark_unknowns_core(min_addr, max_addr, obj=obj, section=section)
                elif obj.segments:
                    for segment in obj.segments:
                        if not segment.memsize:
                            continue
                        min_addr, max_addr = segment.min_addr, segment.max_addr
                        self._mark_unknowns_core(min_addr, max_addr, obj=obj, segment=segment)
                else:
                    # is it empty?
                    _l.warning("Empty ELF object %s.", repr(obj))
            elif isinstance(obj, cle.PE):
                if obj.sections:
                    for section in obj.sections:
                        if not section.memsize:
                            continue
                        min_addr, max_addr = section.min_addr, section.max_addr
                        self._mark_unknowns_core(min_addr, max_addr, obj=obj, section=section)
                else:
                    # is it empty?
                    _l.warning("Empty PE object %s.", repr(obj))
            else:
                min_addr, max_addr = obj.min_addr, obj.max_addr
                self._mark_unknowns_core(min_addr, max_addr, obj=obj)

    def _mark_unknowns_core(self, min_addr, max_addr, obj=None, segment=None, section=None):

        try:
            addr = self.floor_addr(min_addr)
            if addr < min_addr:
                raise KeyError
        except KeyError:
            # there is no other lower address
            try:
                next_addr = self.ceiling_addr(min_addr)
                if next_addr >= max_addr:
                    raise KeyError
            except KeyError:
                next_addr = max_addr

            size = next_addr - min_addr
            if obj is None or isinstance(obj, cle.ExternObject):
                bytes_ = None
            else:
                try:
                    _l.debug("Loading bytes from object %s, section %s, segmeng %s, addresss %#x.",
                             obj, section, segment, min_addr)
                    bytes_ = self.project.loader.memory.load(min_addr, size)
                except KeyError:
                    # The address does not exist
                    bytes_ = None
            self.add_obj(min_addr,
                         Unknown(min_addr, size, bytes_=bytes_, object_=obj, segment=segment, section=section)
                         )

        addr = min_addr
        while addr < max_addr:
            last_addr, last_item = self.floor_item(addr)
            if last_addr < min_addr:
                # impossible
                raise Exception('Impossible')

            if last_item.size == 0:
                # Make sure everything has a non-zero size
                last_item_size = 1
            else:
                last_item_size = last_item.size
            end_addr = last_addr + last_item_size
            if end_addr < max_addr:
                try:
                    next_addr = self.ceiling_addr(end_addr)
                except KeyError:
                    next_addr = max_addr
                if next_addr > end_addr:
                    # there is a gap
                    size = next_addr - end_addr
                    if obj is None or isinstance(obj, cle.ExternObject):
                        bytes_ = None
                    else:
                        try:
                            _l.debug("Loading bytes from object %s, section %s, segmeng %s, addresss %#x.",
                                     obj, section, segment, next_addr)
                            bytes_ = self.project.loader.memory.load(next_addr, size)
                        except KeyError:
                            # The address does not exist
                            bytes_ = None
                    self.add_obj(end_addr,
                                 Unknown(end_addr, size, bytes_=bytes_, object_=obj, segment=segment, section=section)
                                 )
                addr = next_addr
            else:
                addr = max_addr

from angr.analyses import AnalysesHub
AnalysesHub.register_default('CFB', CFBlanket)
AnalysesHub.register_default('CFBlanket', CFBlanket)
<commit_msg>CFBlanket: Fix an off-by-one error in _mark_unknowns_core().<commit_after>import logging
import cffi
import cle

from sortedcontainers import SortedDict

from ..analysis import Analysis

_l = logging.getLogger(name=__name__)

class CFBlanketView:
    """
    A view into the control-flow blanket.
    """
    def __init__(self, cfb):
        self._cfb = cfb

    def __getitem__(self, item):

        if isinstance(item, slice):
            addr = item.start
            start_addr = self._cfb.floor_addr(addr)

            addr_ = start_addr
            while True:
                obj = self._cfb[addr_]
                yield obj

                addr_ += obj
                # Find gaps
                # TODO: finish it
                raise NotImplementedError()

#
# Memory region
#

class MemoryRegion:
    def __init__(self, addr, size, type_, object_, cle_region):
        self.addr = addr
        self.size = size
        self.type = type_
        self.object = object_
        self.cle_region = cle_region

#
# An address can be mapped to one of the following types of object
# - Block
# - MemoryData
# - Unknown
#

class Unknown:
    def __init__(self, addr, size, bytes_=None, object_=None, segment=None, section=None):
        self.addr = addr
        self.size = size

        # Optional
        self.bytes = bytes_
        self.object = object_
        self.segment = segment
        self.section = section

        if size == 0:
            raise Exception("You cannot create an unknown region of size 0.")

    def __repr__(self):
        s = "<Unknown %#x-%#x>" % (self.addr, self.addr + self.size)
        return s

class CFBlanket(Analysis):
    """
    A Control-Flow Blanket is a representation for storing all instructions, data entries, and bytes of a full program.
    """
    def __init__(self, cfg=None):
        self._blanket = SortedDict()

        self._ffi = cffi.FFI()
        self._regions = [ ]

        self._init_regions()

        if cfg is not None:
            self._from_cfg(cfg)
        else:
            _l.debug("CFG is not specified. Initialize CFBlanket from the knowledge base.")
            for func in self.kb.functions.values():
                self.add_function(func)

    def _init_regions(self):

        for obj in self.project.loader.all_objects:
            if isinstance(obj, cle.MetaELF):
                if obj.sections:
                    # Enumerate sections in an ELF file
                    for section in obj.sections:
                        mr = MemoryRegion(section.vaddr, section.memsize, 'TODO', obj, section)
                        self._regions.append(mr)
                else:
                    raise NotImplementedError()
            else:
                mr = MemoryRegion(obj.min_addr, obj.size if hasattr(obj, 'size') else 80, 'TODO', obj, None)
                self._regions.append(mr)

        # Sort them just in case
        self._regions = list(sorted(self._regions, key=lambda x: x.addr))

    @property
    def regions(self):
        """
        Return all memory regions.
        """

        return self._regions

    def floor_addr(self, addr):
        try:
            return next(self._blanket.irange(maximum=addr, reverse=True))
        except StopIteration:
            raise KeyError(addr)

    def floor_item(self, addr):
        key = self.floor_addr(addr)
        return key, self._blanket[key]

    def floor_items(self, addr=None, reverse=False):
        if addr is None:
            start_addr = None
        else:
            try:
                start_addr = next(self._blanket.irange(maximum=addr, reverse=True))
            except StopIteration:
                start_addr = addr

        for key in self._blanket.irange(minimum=start_addr, reverse=reverse):
            yield key, self._blanket[key]

    def ceiling_addr(self, addr):
        try:
            return next(self._blanket.irange(minimum=addr))
        except StopIteration:
            raise KeyError(addr)

    def ceiling_item(self, addr):
        key = self.ceiling_addr(addr)
        return key, self._blanket[key]

    def ceiling_items(self, addr=None, reverse=False, include_first=True):
        if addr is None:
            start_addr = None
        else:
            try:
                start_addr = next(self._blanket.irange(minimum=addr))
            except StopIteration:
                start_addr = addr

        for key in self._blanket.irange(maximum=start_addr if include_first else start_addr - 1, reverse=reverse):
            yield key, self._blanket[key]

    def __getitem__(self, addr):
        return self._blanket[addr]

    def add_obj(self, addr, obj):
        """
        Adds an object `obj` to the blanket at the specified address `addr`
        """
        self._blanket[addr] = obj

    def add_function(self, func):
        """
        Add a function `func` and all blocks of this function to the blanket.
        """
        for block in func.blocks:
            self.add_obj(block.addr, block)

    def dbg_repr(self):
        """
        The debugging representation of this CFBlanket.

        :return:    The debugging representation of this CFBlanket.
        :rtype:     str
        """

        output = [ ]

        for obj in self.project.loader.all_objects:
            for section in obj.sections:
                if section.memsize == 0:
                    continue
                min_addr, max_addr = section.min_addr, section.max_addr
                output.append("### Object %s" % repr(section))
                output.append("### Range %#x-%#x" % (min_addr, max_addr))

                pos = min_addr
                while pos < max_addr:
                    try:
                        addr, thing = self.floor_item(pos)
                        output.append("%#x: %s" % (addr, repr(thing)))

                        if thing.size == 0: pos += 1
                        else: pos += thing.size
                    except KeyError:
                        pos += 1

                output.append("")

        return "\n".join(output)

    def _from_cfg(self, cfg):
        """
        Initialize CFBlanket from a CFG instance.

        :param cfg: A CFG instance.
        :return:    None
        """

        # Let's first add all functions first
        for func in cfg.kb.functions.values():
            self.add_function(func)

        self._mark_unknowns()

    def _mark_unknowns(self):
        """
        Mark all unmapped regions.

        :return: None
        """

        for obj in self.project.loader.all_objects:
            if isinstance(obj, cle.ELF):
                # sections?
                if obj.sections:
                    for section in obj.sections:
                        if not section.memsize or not section.vaddr:
                            continue
                        min_addr, max_addr = section.min_addr, section.max_addr
                        self._mark_unknowns_core(min_addr, max_addr + 1, obj=obj, section=section)
                elif obj.segments:
                    for segment in obj.segments:
                        if not segment.memsize:
                            continue
                        min_addr, max_addr = segment.min_addr, segment.max_addr
                        self._mark_unknowns_core(min_addr, max_addr + 1, obj=obj, segment=segment)
                else:
                    # is it empty?
                    _l.warning("Empty ELF object %s.", repr(obj))
            elif isinstance(obj, cle.PE):
                if obj.sections:
                    for section in obj.sections:
                        if not section.memsize:
                            continue
                        min_addr, max_addr = section.min_addr, section.max_addr
                        self._mark_unknowns_core(min_addr, max_addr + 1, obj=obj, section=section)
                else:
                    # is it empty?
                    _l.warning("Empty PE object %s.", repr(obj))
            else:
                min_addr, max_addr = obj.min_addr, obj.max_addr
                self._mark_unknowns_core(min_addr, max_addr + 1, obj=obj)

    def _mark_unknowns_core(self, min_addr, max_addr, obj=None, segment=None, section=None):

        # The region should be [min_addr, max_addr)

        try:
            addr = self.floor_addr(min_addr)
            if addr < min_addr:
                raise KeyError
        except KeyError:
            # there is no other lower address
            try:
                next_addr = self.ceiling_addr(min_addr)
                if next_addr >= max_addr:
                    raise KeyError
            except KeyError:
                next_addr = max_addr

            size = next_addr - min_addr
            if obj is None or isinstance(obj, cle.ExternObject):
                bytes_ = None
            else:
                try:
                    _l.debug("Loading bytes from object %s, section %s, segmeng %s, addresss %#x.",
                             obj, section, segment, min_addr)
                    bytes_ = self.project.loader.memory.load(min_addr, size)
                except KeyError:
                    # The address does not exist
                    bytes_ = None
            self.add_obj(min_addr,
                         Unknown(min_addr, size, bytes_=bytes_, object_=obj, segment=segment, section=section)
                         )

        addr = min_addr
        while addr < max_addr:
            last_addr, last_item = self.floor_item(addr)
            if last_addr < min_addr:
                # impossible
                raise Exception('Impossible')

            if last_item.size == 0:
                # Make sure everything has a non-zero size
                last_item_size = 1
            else:
                last_item_size = last_item.size
            end_addr = last_addr + last_item_size
            if end_addr < max_addr:
                try:
                    next_addr = self.ceiling_addr(end_addr)
                except KeyError:
                    next_addr = max_addr
                if next_addr > end_addr:
                    # there is a gap
                    size = next_addr - end_addr
                    if obj is None or isinstance(obj, cle.ExternObject):
                        bytes_ = None
                    else:
                        try:
                            _l.debug("Loading bytes from object %s, section %s, segmeng %s, addresss %#x.",
                                     obj, section, segment, next_addr)
                            bytes_ = self.project.loader.memory.load(next_addr, size)
                        except KeyError:
                            # The address does not exist
                            bytes_ = None
                    self.add_obj(end_addr,
                                 Unknown(end_addr, size, bytes_=bytes_, object_=obj, segment=segment, section=section)
                                 )
                addr = next_addr
            else:
                addr = max_addr

from angr.analyses import AnalysesHub
AnalysesHub.register_default('CFB', CFBlanket)
AnalysesHub.register_default('CFBlanket', CFBlanket)
<|endoftext|>


<commit_before>import os
import pytest
import jsonschema
import copy
import numpy as np
import numpy.testing as npt
from pyxrf.core.quant_analysis import (
    save_xrf_standard_yaml_file, load_xrf_standard_yaml_file, _xrf_standard_schema,
    load_included_xrf_standard_yaml_file, compute_standard_element_densities)

# Short example of XRF standard data
_standard_data_sample = [
        {
            "name": "Micromatter 41157",
            "serial": "41157",
            "description": "InSx 22.4 (In=16.0 S=6.4) / SrF2 20.6 / "
                           "Cr 19.8 / Ni 19.2 / GaAs 19.1 (Ga=8.3 As=10.8)",
            "compounds": {
                "In": 16.0,
                "S": 6.4,
                "SrF2": 20.6,
                "Cr": 19.8,
                "Ni": 19.2,
                "Ga": 8.3,
                "As": 10.8
            },
            "density": 101.1
        },
        {
            "name": "Micromatter 41164",
            "serial": "41164",
            "description": "CeF3 21.1 / Au 20.6",
            "compounds": {
                "CeF3": 21.1,
                "Au": 20.6
            }
            # Missing optional 'density' field
        }
    ]

@pytest.mark.parametrize("standard_data", [
    _standard_data_sample,
    []  # The function should also work if the list is empty
])
def test_save_xrf_standard_yaml_file1(tmp_path, standard_data):
    r"""Basic test of function 'save_xrf_standard_yaml_file' and 'load_xrf_standard_yaml_file'"""

    yaml_path = ["yaml", "param", "file"]
    file_name = "standard.yaml"
    yaml_path = os.path.join(tmp_path, *yaml_path, file_name)

    # Sample data
    save_xrf_standard_yaml_file(yaml_path, standard_data)

    data_loaded = load_xrf_standard_yaml_file(yaml_path)

    assert data_loaded == standard_data, \
        "Loaded data is not equal to the original data"

def test_save_xrf_standard_yaml_file2(tmp_path):
    r"""Test the case of of no match between total density and sum of densities of individual compounds"""

    yaml_path = ["yaml", "param", "file"]
    file_name = "standard.yaml"
    yaml_path = os.path.join(tmp_path, *yaml_path, file_name)

    standard_data = []  # No records, but the file will still be saved

    # Sample data
    save_xrf_standard_yaml_file(yaml_path, standard_data)

    # Try to overwrite the file
    with pytest.raises(IOError, match=f"File '{yaml_path}' already exists"):
        save_xrf_standard_yaml_file(yaml_path, standard_data)

    # The following should work
    save_xrf_standard_yaml_file(yaml_path, standard_data, overwrite_existing=True)

def test_save_xrf_standard_yaml_file3(tmp_path):
    r"""Test the case of existing file"""

    yaml_path = ["yaml", "param", "file"]
    file_name = "standard.yaml"
    yaml_path = os.path.join(tmp_path, *yaml_path, file_name)

    standard_data = copy.deepcopy(_standard_data_sample)
    standard_data[0]['density'] = 50.0  # Wrong value of total density

    # Save incorrect data
    save_xrf_standard_yaml_file(yaml_path, standard_data)
    #    and now try to read it
    with pytest.raises(RuntimeError, match="Sum of areal densities does not match total density"):
        load_xrf_standard_yaml_file(yaml_path)

def test_load_xrf_standard_yaml_file1(tmp_path):
    r"""Try loading non-existent YAML file"""

    file_name = "standard.yaml"

    # Try loading from the existing directory
    yaml_path = os.path.join(tmp_path, file_name)
    with pytest.raises(IOError, match=f"File '{yaml_path}' does not exist"):
        load_xrf_standard_yaml_file(yaml_path)

    # Try loading from the non-existing directory
    yaml_path = ["yaml", "param", "file"]
    yaml_path = os.path.join(tmp_path, *yaml_path, file_name)
    with pytest.raises(IOError, match=f"File '{yaml_path}' does not exist"):
        load_xrf_standard_yaml_file(yaml_path)

def test_load_xrf_standard_yaml_file2(tmp_path):
    r"""Test for reporting schema violation"""

    yaml_path = ["yaml", "param", "file"]
    file_name = "standard.yaml"
    yaml_path = os.path.join(tmp_path, *yaml_path, file_name)

    standard_data = _standard_data_sample
    # Change name from string to number (this will not satisfy the built-in schema)
    for v in standard_data:
        v["name"] = 50.36

    # Save the changed dataset
    save_xrf_standard_yaml_file(yaml_path, standard_data)

    with pytest.raises(jsonschema.ValidationError):
        load_xrf_standard_yaml_file(yaml_path)

    # Disable schema validation by setting 'schema=None'
    load_xrf_standard_yaml_file(yaml_path, schema=None)

    # Change the schema to match data and validate with changed schema
    schema = copy.deepcopy(_xrf_standard_schema)
    schema['properties']['name'] = {"type": ["string", "number"]}
    standard_data_out = load_xrf_standard_yaml_file(yaml_path, schema=schema)
    assert standard_data_out == standard_data, \
        "Loaded data is different from the original"

def test_load_included_xrf_standard_yaml_file():

    data = load_included_xrf_standard_yaml_file()
    assert len(data) > 1, "Standard YAML file can not be read"

def test_compute_standard_element_densities():

    standard_data = _standard_data_sample

    for data in standard_data:

        if "density" in data:
            total_density = data["density"]
        else:
            total_density = np.sum(list(data["compounds"].values()))

        element_densities = compute_standard_element_densities(data["compounds"])

        npt.assert_almost_equal(np.sum(list(element_densities.values())), total_density,
                                err_msg="The sum of element densities and the total sum don't match")
<commit_msg>Additional tests for 'compute_standard_element_densities'<commit_after>import os
import pytest
import jsonschema
import copy
import numpy as np
import numpy.testing as npt
from pyxrf.core.xrf_utils import validate_element_str
from pyxrf.core.quant_analysis import (
    save_xrf_standard_yaml_file, load_xrf_standard_yaml_file, _xrf_standard_schema,
    load_included_xrf_standard_yaml_file, compute_standard_element_densities)

# Short example of XRF standard data
_standard_data_sample = [
        {
            "name": "Micromatter 41157",
            "serial": "41157",
            "description": "InSx 22.4 (In=16.0 S=6.4) / SrF2 20.6 / "
                           "Cr 19.8 / Ni 19.2 / GaAs 19.1 (Ga=8.3 As=10.8)",
            "compounds": {
                "In": 16.0,
                "S": 6.4,
                "SrF2": 20.6,
                "Cr": 19.8,
                "Ni": 19.2,
                "Ga": 8.3,
                "As": 10.8
            },
            "density": 101.1
        },
        {
            "name": "Micromatter 41164",
            "serial": "41164",
            "description": "CeF3 21.1 / Au 20.6",
            "compounds": {
                "CeF3": 21.1,
                "Au": 20.6
            }
            # Missing optional 'density' field
        }
    ]

@pytest.mark.parametrize("standard_data", [
    _standard_data_sample,
    []  # The function should also work if the list is empty
])
def test_save_xrf_standard_yaml_file1(tmp_path, standard_data):
    r"""Basic test of function 'save_xrf_standard_yaml_file' and 'load_xrf_standard_yaml_file'"""

    yaml_path = ["yaml", "param", "file"]
    file_name = "standard.yaml"
    yaml_path = os.path.join(tmp_path, *yaml_path, file_name)

    # Sample data
    save_xrf_standard_yaml_file(yaml_path, standard_data)

    data_loaded = load_xrf_standard_yaml_file(yaml_path)

    assert data_loaded == standard_data, \
        "Loaded data is not equal to the original data"

def test_save_xrf_standard_yaml_file2(tmp_path):
    r"""Test the case of of no match between total density and sum of densities of individual compounds"""

    yaml_path = ["yaml", "param", "file"]
    file_name = "standard.yaml"
    yaml_path = os.path.join(tmp_path, *yaml_path, file_name)

    standard_data = []  # No records, but the file will still be saved

    # Sample data
    save_xrf_standard_yaml_file(yaml_path, standard_data)

    # Try to overwrite the file
    with pytest.raises(IOError, match=f"File '{yaml_path}' already exists"):
        save_xrf_standard_yaml_file(yaml_path, standard_data)

    # The following should work
    save_xrf_standard_yaml_file(yaml_path, standard_data, overwrite_existing=True)

def test_save_xrf_standard_yaml_file3(tmp_path):
    r"""Test the case of existing file"""

    yaml_path = ["yaml", "param", "file"]
    file_name = "standard.yaml"
    yaml_path = os.path.join(tmp_path, *yaml_path, file_name)

    standard_data = copy.deepcopy(_standard_data_sample)
    standard_data[0]['density'] = 50.0  # Wrong value of total density

    # Save incorrect data
    save_xrf_standard_yaml_file(yaml_path, standard_data)
    #    and now try to read it
    with pytest.raises(RuntimeError, match="Sum of areal densities does not match total density"):
        load_xrf_standard_yaml_file(yaml_path)

def test_load_xrf_standard_yaml_file1(tmp_path):
    r"""Try loading non-existent YAML file"""

    file_name = "standard.yaml"

    # Try loading from the existing directory
    yaml_path = os.path.join(tmp_path, file_name)
    with pytest.raises(IOError, match=f"File '{yaml_path}' does not exist"):
        load_xrf_standard_yaml_file(yaml_path)

    # Try loading from the non-existing directory
    yaml_path = ["yaml", "param", "file"]
    yaml_path = os.path.join(tmp_path, *yaml_path, file_name)
    with pytest.raises(IOError, match=f"File '{yaml_path}' does not exist"):
        load_xrf_standard_yaml_file(yaml_path)

def test_load_xrf_standard_yaml_file2(tmp_path):
    r"""Test for reporting schema violation"""

    yaml_path = ["yaml", "param", "file"]
    file_name = "standard.yaml"
    yaml_path = os.path.join(tmp_path, *yaml_path, file_name)

    standard_data = _standard_data_sample
    # Change name from string to number (this will not satisfy the built-in schema)
    for v in standard_data:
        v["name"] = 50.36

    # Save the changed dataset
    save_xrf_standard_yaml_file(yaml_path, standard_data)

    with pytest.raises(jsonschema.ValidationError):
        load_xrf_standard_yaml_file(yaml_path)

    # Disable schema validation by setting 'schema=None'
    load_xrf_standard_yaml_file(yaml_path, schema=None)

    # Change the schema to match data and validate with changed schema
    schema = copy.deepcopy(_xrf_standard_schema)
    schema['properties']['name'] = {"type": ["string", "number"]}
    standard_data_out = load_xrf_standard_yaml_file(yaml_path, schema=schema)
    assert standard_data_out == standard_data, \
        "Loaded data is different from the original"

def test_load_included_xrf_standard_yaml_file():

    data = load_included_xrf_standard_yaml_file()
    assert len(data) > 1, "Standard YAML file can not be read"

def test_compute_standard_element_densities():

    standard_data = _standard_data_sample

    for data in standard_data:

        # Find total density
        if "density" in data:
            total_density = data["density"]
        else:
            total_density = np.sum(list(data["compounds"].values()))

        element_densities = compute_standard_element_densities(data["compounds"])

        # Validate that all the keys of the returned dictionary represent elements
        assert all([validate_element_str(_) for _ in element_densities.keys()]), \
            f"Some of the elements in the list {list(element_densities.keys())} have invalid representation"

        # Check if the sum of all return densities equals total density
        npt.assert_almost_equal(np.sum(list(element_densities.values())), total_density,
                                err_msg="The sum of element densities and the total sum don't match")
<|endoftext|>


<commit_before>import inspect as _inspect
import os as _os
import sys as _sys
import pyximport; pyximport.install()

_sys.path.append('')
_starting_dir = _os.getcwd()
_cmd_folder = _os.path.realpath(_os.path.abspath(_os.path.split(_inspect.getfile(_inspect.currentframe()))[0]))
_os.chdir(_cmd_folder)

try:
    from settings import global_settings
    import ampal
    import ampal.specifications as specifications
    from ampal import analyse_protein
    from ampal import interactions
    import buff
    import external_programs
    import tools
    import tools.geometry as geometry
    import optimisation
    with open('logo.txt', 'r') as inf:
        logo = ''.join(inf.readlines()[:51])
finally:
    _os.chdir(_starting_dir)

__version__ = "0.4.0"
<commit_msg>Now runs `configure.py` if `settings.json` is not found.<commit_after>import inspect as _inspect
import os as _os
import subprocess as _subprocess
import sys as _sys
import pyximport; pyximport.install()

_sys.path.append('')
_starting_dir = _os.getcwd()
_cmd_folder = _os.path.realpath(_os.path.abspath(_os.path.split(_inspect.getfile(_inspect.currentframe()))[0]))
_os.chdir(_cmd_folder)

try:
    if 'settings.json' not in _os.listdir(_cmd_folder):
        print('No configuration file (settings.json) found in {}.\nRunning configure.py...\n'.format(_cmd_folder))
        _subprocess.call(['python', 'configure.py'])
    from settings import global_settings
    import ampal
    import ampal.specifications as specifications
    from ampal import analyse_protein
    from ampal import interactions
    import buff
    import external_programs
    import tools
    import tools.geometry as geometry
    import optimisation
    with open('logo.txt', 'r') as inf:
        logo = ''.join(inf.readlines()[:51])
finally:
    _os.chdir(_starting_dir)

__version__ = "0.4.0"
<|endoftext|>


<commit_before># germ.py

import itertools, random, math

class Germ:

    germ_colors = ["green", "magenta", "purple", "yellow", "cyan", "lavenderblush", "salmon"]
    speed = 15 # This is an angle, mind you.

    def __init__(self, state, canvas: "tkinter.canvas", xy: (int, int), bearing: float, color):
        """
            Creates a germ given the canvas on which to create it, the coordinates, color, and initial velocity.

            canvas - the tkinter canvas that the germ is being created on
            xy - coordinates; location of the germ. To prevent sticking, must be between 0 and bounding area, _exclusively_.
            color - a tkinter-viable color (can be hex)
        """
        # 'Adopts' the canvas, and then creates itself on the canvas with the color given.
        # Then moves itself to the given xy coordinate.
        self.state = state
        self.canvas = canvas
        self.bearing = bearing
        self.body = self.canvas.create_oval(0, 0, 11, 11, fill=color, tags="germ")
        self.canvas.move(self.body, *xy)

        self.dead = False
        self.color = color # Saving this mostly just for debugging purposes.

    @classmethod
    def from_random(cls, state, canvas: "tkintercanvas"):
        """
            Creates a germ with a random position, color, and velocity. Needs some input, though.

            cls - the current class. Needed to make this a classmethod
            canvas - the tkinter canvas that the germ is being created on
        """
        xy = (random.randint(1, canvas.winfo_width()), random.randint(1, canvas.winfo_height()))
        bearing = random.randrange(360)
        color = random.choice(cls.germ_colors)
        return cls(state, canvas, xy, bearing, color)

    def move(self, direction: int, moving: int):
        """
            Moves the germ based on its velocity. Bounces off walls.

            direction - A signed integer. If negative, pivot left. If positive, pivot right.
            moving - Also a signed integer. If negative, don't move. If positive, move.
        """
        def oval_center(bounding_box):
            x = math.floor((bounding_box[0] + bounding_box[2]) / 2)
            y = math.floor((bounding_box[1] + bounding_box[3]) / 2)
            return (x, y)

        def rotate_point(xy, pivot_xy, angle):
            """
                Rotates a point xy around another point pivot_xy by angle degrees.
            """
            angle = -angle if direction > 0 else angle  # Flip the angle to get clockwise rotation when pivoting to the right.
            angle = math.radians(angle)
            xy = list(xy)   # Make xy mutable; it's a tossaway variable anyway.

            # Move to the origin.
            xy[0] -= pivot_xy[0]
            xy[1] -= pivot_xy[1]

            # Rotate the point.
            new_x = xy[0] * math.cos(angle) + xy[1] * math.sin(angle)
            new_y = -xy[0] * math.sin(angle) + xy[1] * math.cos(angle)

            # Move back.
            new_x += pivot_xy[0]
            new_y += pivot_xy[1]

            return (new_x, new_y)

        pivots_bearing = self.bearing + direction * math.degrees(math.atan(.75))  # Multiply by direction to get whether to subtract or add to self.bearing.
        body = oval_center(self.canvas.bbox(self.body))
        pivot = (10 * math.cos(math.radians(pivots_bearing)) + body[0],
                 10 * math.sin(math.radians(pivots_bearing)) + body[1])
        speed = Germ.speed if moving > 0 else 0

        body_center = rotate_point(oval_center(self.canvas.bbox(self.body)), pivot, speed)
        self.bearing = (self.bearing + speed * direction) % 360

        self.canvas.coords(self.body, (body_center[0] - 5, body_center[1] - 5, body_center[0] + 5, body_center[1] + 5))

        self.collision()    # Check for collisions with planks or germs.

    def collision(self):
        """
            Checks for collisions with other objects, and reacts accordingly.
        """
        intruders = list(self.canvas.find_overlapping(*self.canvas.bbox(self.body)))
        intruders.remove(self.body)    # Remove itself from the list.
        for intruder in intruders:
            if "plank" in self.canvas.gettags(intruder):
                # Kill both parties if colliding with a plank.
                for citizen in self.state():
                    if citizen.body == intruder: citizen.die()
                self.die()

            elif "germ" in self.canvas.gettags(intruder):
                print("Oh hi friend!")

    def die(self):
        self.canvas.delete(self.body)
        self.dead = True
<commit_msg>Germs now bounce off of each other when they touch. The process is through teleportation, though, so that may or may not cause problems further along.<commit_after># germ.py

import itertools, random, math

class Germ:

    germ_colors = ["green", "magenta", "purple", "yellow", "cyan", "lavenderblush", "salmon"]
    speed = 15 # This is an angle, mind you.

    def __init__(self, state, canvas: "tkinter.canvas", xy: (int, int), bearing: float, color):
        """
            Creates a germ given the canvas on which to create it, the coordinates, color, and initial velocity.

            canvas - the tkinter canvas that the germ is being created on
            xy - coordinates; location of the germ. To prevent sticking, must be between 0 and bounding area, _exclusively_.
            color - a tkinter-viable color (can be hex)
        """
        # 'Adopts' the canvas, and then creates itself on the canvas with the color given.
        # Then moves itself to the given xy coordinate.
        self.state = state
        self.canvas = canvas
        self.bearing = bearing
        self.body = self.canvas.create_oval(0, 0, 11, 11, fill=color, tags="germ")
        self.canvas.move(self.body, *xy)

        self.dead = False
        self.color = color # Saving this mostly just for debugging purposes.

    @classmethod
    def from_random(cls, state, canvas: "tkintercanvas"):
        """
            Creates a germ with a random position, color, and velocity. Needs some input, though.

            cls - the current class. Needed to make this a classmethod
            canvas - the tkinter canvas that the germ is being created on
        """
        xy = (random.randint(1, canvas.winfo_width()), random.randint(1, canvas.winfo_height()))
        bearing = random.randrange(360)
        color = random.choice(cls.germ_colors)
        return cls(state, canvas, xy, bearing, color)

    @staticmethod
    def oval_center(bounding_box):
        x = math.floor((bounding_box[0] + bounding_box[2]) / 2)
        y = math.floor((bounding_box[1] + bounding_box[3]) / 2)
        return (x, y)

    def move(self, direction: int, moving: int):
        """
            Moves the germ based on its velocity. Bounces off walls.

            direction - A signed integer. If negative, pivot left. If positive, pivot right.
            moving - Also a signed integer. If negative, don't move. If positive, move.
        """
        def rotate_point(xy, pivot_xy, angle):
            """
                Rotates a point xy around another point pivot_xy by angle degrees.
            """
            angle = -angle if direction > 0 else angle  # Flip the angle to get clockwise rotation when pivoting to the right.
            angle = math.radians(angle)
            xy = list(xy)   # Make xy mutable; it's a tossaway variable anyway.

            # Move to the origin.
            xy[0] -= pivot_xy[0]
            xy[1] -= pivot_xy[1]

            # Rotate the point.
            new_x = xy[0] * math.cos(angle) + xy[1] * math.sin(angle)
            new_y = -xy[0] * math.sin(angle) + xy[1] * math.cos(angle)

            # Move back.
            new_x += pivot_xy[0]
            new_y += pivot_xy[1]

            return (new_x, new_y)

        pivots_bearing = self.bearing + direction * math.degrees(math.atan(.75))  # Multiply by direction to get whether to subtract or add to self.bearing.
        body = Germ.oval_center(self.canvas.bbox(self.body))
        pivot = (10 * math.cos(math.radians(pivots_bearing)) + body[0],
                 10 * math.sin(math.radians(pivots_bearing)) + body[1])
        speed = Germ.speed if moving > 0 else 0

        body_center = rotate_point(Germ.oval_center(self.canvas.bbox(self.body)), pivot, speed)
        self.bearing = (self.bearing + speed * direction) % 360

        self.canvas.coords(self.body, (body_center[0] - 5, body_center[1] - 5, body_center[0] + 5, body_center[1] + 5))

        self.collision()    # Check for collisions with planks or germs.

    def collision(self):
        """
            Checks for collisions with other objects, and reacts accordingly.
        """
        intruders = list(self.canvas.find_overlapping(*self.canvas.bbox(self.body)))
        intruders.remove(self.body)    # Remove itself from the list.
        for intruder in intruders:
            if "plank" in self.canvas.gettags(intruder):
                # Kill both parties if colliding with a plank.
                for citizen in self.state():
                    if citizen.body == intruder: citizen.die()
                self.die()

            elif "germ" in self.canvas.gettags(intruder):
                # If two germs bounce into each other, they'll bounce away from each other
                self_xy = Germ.oval_center(self.canvas.bbox(self.body))
                other_xy = Germ.oval_center(self.canvas.bbox(intruder))
                offset_y = other_xy[1] - self_xy[1]
                offset_x = other_xy[0] - self_xy[0]
                self_new = (self_xy[0] - .5 * offset_x, self_xy[1] - .5 * offset_y)
                other_new = (other_xy[0] + .5 * offset_x, other_xy[1] + .5 * offset_y)

                # Apply the new repercussion-ed coordinates
                self.canvas.coords(self.body, (self_new[0] - 5, self_new[1] - 5, self_new[0] + 5, self_new[1] + 5))
                self.canvas.coords(intruder, (other_new[0] - 5, other_new[1] - 5, other_new[0] + 5, other_new[1] + 5))

    def die(self):
        self.canvas.delete(self.body)
        self.dead = True
<|endoftext|>


<commit_before>import pytest
from thingstance import Thing
from thingstance.stores.mongodb import MongoStore
from pymongo import Connection

database = 'testing_things'

Connection().drop_database(database)
store = MongoStore(database=database)

def test_memory_store():
    thing = Thing()
    empty_hash = thing.hash
    store.put(thing)

    thing = Thing(text='Foo Value')
    foo_hash = thing.hash
    store.put(thing)

    thing = Thing(text='Bar Value')
    bar_hash = thing.hash
    store.put(thing)

    thing = store.get(empty_hash)
    assert thing.hash == empty_hash

    thing = store.get(foo_hash)
    assert thing.hash == foo_hash
    assert thing.text == 'Foo Value'

    thing = store.get(bar_hash)
    assert thing.hash == bar_hash
    assert thing.text == 'Bar Value'

def test_mongodb_get_latest_by_name():
    with pytest.raises(NotImplementedError):
        store.get_latest(name="toves")
<commit_msg>Idempotent and name passing mongo tests<commit_after>import pytest
from thingstance import Thing
from thingstance.stores.mongodb import MongoStore
from pymongo import Connection

database = 'testing_things'

Connection().drop_database(database)
store = MongoStore(database=database)

def test_memory_store():
    thing = Thing()
    empty_hash = thing.hash
    store.put(thing)

    thing = Thing(text='Foo Value')
    foo_hash = thing.hash
    store.put(thing)

    thing = Thing(text='Bar Value')
    bar_hash = thing.hash
    store.put(thing)

    thing = store.get(empty_hash)
    assert thing.hash == empty_hash

    thing = store.get(foo_hash)
    assert thing.hash == foo_hash
    assert thing.text == 'Foo Value'

    thing = store.get(bar_hash)
    assert thing.hash == bar_hash
    assert thing.text == 'Bar Value'

def test_mongodb_get_latest_by_name():
    with pytest.raises(NotImplementedError):
        store.get_latest(name="toves")

def test_own_database_and_collection():
    database = 'testing_named_things'
    collection = 'testing_collection'
    store = MongoStore(database=database, collection=collection)
    assert store.db.name == database
    assert store.coll.name == collection

def test_own_db():
    database = 'testing_other_things'
    db = Connection()[database]
    store = MongoStore(db=db)
    assert store.db == db
    assert store.db.name == database

def test_idempotent_put():
    thing = Thing(text='Idempotent?')
    store.put(thing)
    store.put(thing)
    store.put(thing)
<|endoftext|>