<commit_before># -*- coding: utf-8 -*-
##############################################################################
#
#    Author: Alexandre Fayolle
#    Copyright 2014 Camptocamp SA
#
#    This program 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.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU Affero General Public License for more details.
#
#    You should have received a copy of the GNU Affero General Public License
#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################

from openerp import SUPERUSER_ID
from openerp.osv import orm, fields
from openerp.tools.translate import _

class StockWarehouse(orm.Model):
    _inherit = 'stock.warehouse'

    _columns = {
        'reception_steps': fields.selection(
            [('one_step',
              'Receive goods directly in stock (1 step)'
              ),
             ('two_steps',
              'Unload in input location then go to stock (2 steps)'
              ),
             ('three_steps',
              'Unload in input location, go through a quality control before '
              'being admitted in stock (3 steps)'
              ),
             ('transit_one_step',
              'Receive goods directly in stock from Transit (transit + 1 step)'
              ),
             ('transit_two_steps',
              'Unload in input location from Transit then go to stock '
              '(transit + 2 steps)'
              ),
             ('transit_three_steps',
              'Unload in input location from Transit, go through a quality '
              'control before being admitted in stock (transit + 3 steps)'
              ),
             ],
            'Incoming Shipments',
            help="Default incoming route to follow", required=True),

        'delivery_steps': fields.selection(
            [('ship_only',
              'Ship directly from stock (Ship only)'
              ),
             ('pick_ship',
              'Bring goods to output location before shipping (Pick + Ship)'
              ),
             ('pick_pack_ship',
              'Make packages into a dedicated location, then bring them to '
              'the output location for shipping (Pick + Pack + Ship)'
              ),
             ('ship_transit',
              'Ship from stock to Transit location'
              ),
             ('pick_ship_transit',
              'Bring goods to output location before shipping to Transit'
              ),
             ('pick_pack_ship_transit',
              'Make packages into a dedicated location, then bring them to '
              'the output location for shipping to transit'
              ),
             ],
            'Outgoing Shippings',
            help="Default outgoing route to follow", required=True),

        'transit_in_type_id': fields.many2one('stock.picking.type',
                                              'In Transit Type'),
        'transit_out_type_id': fields.many2one('stock.picking.type',
                                               'Out Transit Type'),
        'wh_transit_in_loc_id': fields.many2one('stock.location',
                                                'Incoming Transit'),
        'wh_transit_out_loc_id': fields.many2one('stock.location',
                                                 'Outgoing Transit'),
    }

    def create(self, cr, uid, vals, context=None):
        transit_in, transit_out = self._create_transit_locations(
            cr, uid,
            vals.get('company_id'),
            vals.get('reception_steps', ''),
            vals.get('delivery_steps', ''),
            context)
        vals['wh_transit_in_loc_id'] = transit_in
        vals['wh_transit_out_loc_id'] = transit_out
        return super(StockWarehouse, self).create(cr, uid, vals, context)

    def _create_transit_locations(self, cr, uid,
                                  company_id,
                                  reception_steps,
                                  delivery_steps,
                                  context):
        if context is None:
            context = {}
        ctx = context.copy()
        ctx['active_test'] = False
        data_obj = self.pool.get('ir.model.data')
        location_obj = self.pool.get('stock.location')
        try:
            out_id = data_obj.get_object_reference(
                cr, uid, 'stock_route_transit', 'transit_outgoing')[1]
        except:
            out_id = location_obj.create(
                cr, uid,
                {'name': _('Outgoing Transit'),
                 'usage': 'transit',
                 'active': ('transit' in delivery_steps),
                 'company_id': company_id,
                 },
                context=ctx
                )
        in_id = location_obj.create(cr, uid,
                                    {'name': _('Incoming Transit'),
                                     'usage': 'transit',
                                     'active': ('transit' in reception_steps),
                                     'company_id': company_id,
                                     },
                                    context=ctx)
        return in_id, out_id

    def get_routes_dict(self, cr, uid, ids, warehouse, context=None):
        """return a dict of routes. Keys are the possible reception/delivery steps,
        values are tuples of 2 elements:
        1. the name of the route
        2. a list of 0, 1 or 2 tuples of (from_loc, dest_loc, pick_type_id),
           giving the different steps of the route.
        The list is processed by `_get_push_pull_rules`.

        """
        _super = super(StockWarehouse, self)
        routes_dict = _super.get_routes_dict(cr, uid, ids, warehouse, context)
        customer_loc, supplier_loc = self._get_partner_locations(
            cr, uid, ids, context=context)
        if not (warehouse.wh_transit_out_loc_id
                and warehouse.wh_transit_in_loc_id):
            # this can happen for warehouses created before this module was
            # installed
            in_id, out_id = self._create_transit_locations(
                cr, uid,
                warehouse.company_id.id,
                warehouse.reception_steps,
                warehouse.delivery_steps,
                context)
            warehouse.write(
                {'wh_transit_in_loc_id': in_id,
                 'wh_transit_out_loc_id': out_id}
                )
        new_routes = {
            'transit_one_step': (_('Receipt in 1 step from Transit'),
                                 [(warehouse.wh_transit_in_loc_id,
                                   warehouse.lot_stock_id,
                                   warehouse.in_type_id.id
                                   ),
                                  ]
                                 ),
            'transit_two_steps': (_('Receipt in 2 steps from Transit'),
                                  [(warehouse.wh_transit_in_loc_id,
                                    warehouse.wh_input_stock_loc_id,
                                    warehouse.in_type_id.id,
                                    ),
                                   (warehouse.wh_input_stock_loc_id,
                                    warehouse.lot_stock_id,
                                    warehouse.in_type_id.id,
                                    ),
                                   ]
                                  ),
            'transit_three_steps': (_('Receipt in 3 steps from Transit'),
                                    [(warehouse.wh_transit_in_loc_id,
                                      warehouse.wh_input_stock_loc_id,
                                      warehouse.in_type_id.id,
                                      ),
                                     (warehouse.wh_input_stock_loc_id,
                                      warehouse.wh_qc_stock_loc_id,
                                      warehouse.int_type_id.id
                                      ),
                                     (warehouse.wh_qc_stock_loc_id,
                                      warehouse.lot_stock_id,
                                      warehouse.int_type_id.id
                                      ),
                                     ]
                                    ),
            'ship_transit': (_('Ship to Transit'),
                             [(warehouse.lot_stock_id,
                               warehouse.wh_transit_out_loc_id,
                               warehouse.out_type_id.id
                               ),
                              (warehouse.wh_transit_out_loc_id,
                               customer_loc,
                               warehouse.transit_out_type_id.id
                               ),
                              ]
                             ),
            'pick_ship_transit': (_('Pick + Ship + Transit'),
                                  [(warehouse.lot_stock_id,
                                    warehouse.wh_output_stock_loc_id,
                                    warehouse.pick_type_id.id
                                    ),
                                   (warehouse.wh_output_stock_loc_id,
                                    warehouse.wh_transit_out_loc_id,
                                    warehouse.out_type_id.id
                                    ),
                                   (warehouse.wh_transit_out_loc_id,
                                    customer_loc,
                                    warehouse.transit_out_type_id.id
                                    ),
                                   ]
                                  ),
            'pick_pack_ship_transit': (_('Pick + Pack + Ship + Transit'),
                                       [(warehouse.lot_stock_id,
                                         warehouse.wh_pack_stock_loc_id,
                                         warehouse.pick_type_id.id
                                         ),
                                        (warehouse.wh_pack_stock_loc_id,
                                         warehouse.wh_output_stock_loc_id,
                                         warehouse.pack_type_id.id
                                         ),
                                        (warehouse.wh_output_stock_loc_id,
                                         warehouse.wh_transit_out_loc_id,
                                         warehouse.out_type_id.id
                                         ),
                                        (warehouse.wh_transit_out_loc_id,
                                         customer_loc,
                                         warehouse.transit_out_type_id.id
                                         ),
                                        ]
                                       ),
        }
        routes_dict.update(new_routes)
        return routes_dict

    def switch_location(self, cr, uid, ids,
                        warehouse,
                        new_reception_step=False,
                        new_delivery_step=False,
                        context=None):
        """set unused locations to active=False"""
        if not (warehouse.wh_transit_out_loc_id
                and warehouse.wh_transit_in_loc_id):
            # this can happen for warehouses created before this module was
            # installed
            in_id, out_id = self._create_transit_locations(
                cr, uid,
                warehouse.company_id.id,
                warehouse.reception_steps,
                warehouse.delivery_steps,
                context)
            warehouse.write(
                {'wh_transit_in_loc_id': in_id,
                 'wh_transit_out_loc_id': out_id})
        # incoming transit
        other_wh_ids = self.search(cr, uid,
                                   [('id', '!=', warehouse.id),
                                    ('wh_transit_in_loc_id', '=',
                                     warehouse.wh_transit_in_loc_id.id)
                                    ],
                                   context=context)
        other_wh = self.browse(cr, uid, other_wh_ids, context=context)
        transit_receptions = ['transit' in (new_reception_step or '')] + \
                             ['transit' in other.reception_steps
                              for other in other_wh]
        warehouse.wh_transit_in_loc_id.active = any(transit_receptions)
        # outgoing transit
        other_wh_ids = self.search(cr, uid,
                                   [('id', '!=', warehouse.id),
                                    ('wh_transit_in_loc_id', '=',
                                     warehouse.wh_transit_out_loc_id.id)
                                    ],
                                   context=context)
        other_wh = self.browse(cr, uid, other_wh_ids, context=context)
        transit_deliveries = ['transit' in (new_delivery_step or '')] + \
                             ['transit' in other.delivery_steps
                              for other in other_wh]
        print transit_deliveries
        warehouse.wh_transit_in_loc_id.active = any(transit_deliveries)
        return super(StockWarehouse, self).switch_location(cr, uid, ids,
                                                           warehouse,
                                                           new_reception_step,
                                                           new_delivery_step,
                                                           context)

    def change_route(self, cr, uid, ids,
                     warehouse,
                     new_reception_step=False,
                     new_delivery_step=False,
                     context=None):
        """change input_loc, output_loc
        update active fiels on picking_types

                update location_dest (resp. src) of in (resp. out) picking type
        remove all routes of the WH and recreate them
        """
        super(StockWarehouse, self).change_route(cr, uid, ids,
                                                 warehouse,
                                                 new_reception_step,
                                                 new_delivery_step,
                                                 context)
        if 'transit' not in new_delivery_step and \
          'transit' not in new_reception_step:
            return True
        # due to poor design in base class, we need to redo everything... :-(
        # and add our stuff
        picking_type_obj = self.pool.get('stock.picking.type')
        pull_obj = self.pool.get('procurement.rule')
        push_obj = self.pool.get('stock.location.path')
        route_obj = self.pool.get('stock.location.route')
        new_reception_step = new_reception_step or warehouse.reception_steps
        new_delivery_step = new_delivery_step or warehouse.delivery_steps
        if new_reception_step in ('transit_one_step', 'one_step'):
            input_loc = warehouse.lot_stock_id
        else:
            input_loc = warehouse.wh_input_stock_loc_id
        if new_delivery_step in ('ship_transit', 'ship_only'):
            output_loc = warehouse.lot_stock_id
        else:
            output_loc = warehouse.wh_output_stock_loc_id

        wh = warehouse
        picking_type_writes = [
            (wh.in_type_id.id, {'default_location_dest_id': input_loc.id}),
            (wh.out_type_id.id, {'default_location_src_id': output_loc.id}),
            (wh.pick_type_id.id,
             {'active': new_delivery_step in ('ship_only', 'ship_transit')}),
            (wh.pack_type_id.id,
             {'active': new_delivery_step.startswith('pick_pack_ship')}),
            (wh.transit_in_type_id.id,
             {'active': 'transit' in new_reception_step}),
            (wh.transit_out_type_id.id,
             {'active': 'transit' in new_reception_step}),
        ]
        for pick_type_id, vals in picking_type_writes:
            picking_type_obj.write(
                cr, uid, pick_type_id, vals, context=context)

        # fix active field of the crossdock route
        if new_reception_step.endswith('one_step'):
            cross_dock_active = False
        elif new_delivery_step in ('ship_transit', 'ship_only'):
            cross_dock_active = False
        else:
            cross_dock_active = True
        route_obj.write(cr, uid,
                        warehouse.crossdock_route_id.id,
                        {'active': cross_dock_active},
                        context=context)

        return True

    def create_sequences_and_picking_types(self, cr, uid, warehouse, context=None):
        _super = super(StockWarehouse, self)
        _super.create_sequences_and_picking_types(cr, uid, warehouse, context)
        seq_obj = self.pool.get('ir.sequence')
        picking_type_obj = self.pool.get('stock.picking.type')
        # create new sequences
        in_transit_seq_id = seq_obj.create(cr,
                                           SUPERUSER_ID,
                                           values={'name': warehouse.name + _(' Sequence incoming transit'),
                                                   'prefix': warehouse.code + '/TR-IN/',
                                                   'padding': 5},
                                           context=context)
        out_transit_seq_id = seq_obj.create(cr,
                                            SUPERUSER_ID,
                                            values={'name': warehouse.name + _(' Sequence outgoing transit'),
                                                    'prefix': warehouse.code + '/TR-OUT/',
                                                    'padding': 5},
                                            context=context)
        customer_loc, supplier_loc = self._get_partner_locations(
            cr, uid, warehouse.id, context=context)
        in_transit_type = picking_type_obj.create(cr, uid,
                                                  {'name': _('In Transit'),
                                                   'warehouse_id': warehouse.id,
                                                   'code': 'incoming',
                                                   'sequence_id': in_transit_seq_id,
                                                   'default_location_src_id': supplier_loc.id,
                                                   'default_location_dest_id': warehouse.wh_input_stock_loc_id.id,
                                                   'active': 'transit' in warehouse.reception_steps,
                                                   },
                                                  context=context)
        out_transit_type = picking_type_obj.create(cr, uid,
                                                   {'name': _('Out Transit'),
                                                    'warehouse_id': warehouse.id,
                                                    'code': 'outgoing',
                                                    'sequence_id': in_transit_seq_id,
                                                    'default_location_src_id': warehouse.wh_output_stock_loc_id.id,
                                                    'default_location_dest_id': customer_loc.id,
                                                    'active': 'transit' in warehouse.delivery_steps,
                                                    },
                                                   context=context)
        self.write(cr, uid, warehouse.id,
                   {'transit_in_type_id': in_transit_type,
                    'transit_out_type_id': out_transit_type,
                    },
                   context=context)
<commit_msg>refactored duplicated code<commit_after># -*- coding: utf-8 -*-
##############################################################################
#
#    Author: Alexandre Fayolle
#    Copyright 2014 Camptocamp SA
#
#    This program 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.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU Affero General Public License for more details.
#
#    You should have received a copy of the GNU Affero General Public License
#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################

from openerp import SUPERUSER_ID
from openerp.osv import orm, fields
from openerp.tools.translate import _

class StockWarehouse(orm.Model):
    _inherit = 'stock.warehouse'

    _columns = {
        'reception_steps': fields.selection(
            [('one_step',
              'Receive goods directly in stock (1 step)'
              ),
             ('two_steps',
              'Unload in input location then go to stock (2 steps)'
              ),
             ('three_steps',
              'Unload in input location, go through a quality control before '
              'being admitted in stock (3 steps)'
              ),
             ('transit_one_step',
              'Receive goods directly in stock from Transit (transit + 1 step)'
              ),
             ('transit_two_steps',
              'Unload in input location from Transit then go to stock '
              '(transit + 2 steps)'
              ),
             ('transit_three_steps',
              'Unload in input location from Transit, go through a quality '
              'control before being admitted in stock (transit + 3 steps)'
              ),
             ],
            'Incoming Shipments',
            help="Default incoming route to follow", required=True),

        'delivery_steps': fields.selection(
            [('ship_only',
              'Ship directly from stock (Ship only)'
              ),
             ('pick_ship',
              'Bring goods to output location before shipping (Pick + Ship)'
              ),
             ('pick_pack_ship',
              'Make packages into a dedicated location, then bring them to '
              'the output location for shipping (Pick + Pack + Ship)'
              ),
             ('ship_transit',
              'Ship from stock to Transit location'
              ),
             ('pick_ship_transit',
              'Bring goods to output location before shipping to Transit'
              ),
             ('pick_pack_ship_transit',
              'Make packages into a dedicated location, then bring them to '
              'the output location for shipping to transit'
              ),
             ],
            'Outgoing Shippings',
            help="Default outgoing route to follow", required=True),

        'transit_in_type_id': fields.many2one('stock.picking.type',
                                              'In Transit Type'),
        'transit_out_type_id': fields.many2one('stock.picking.type',
                                               'Out Transit Type'),
        'wh_transit_in_loc_id': fields.many2one('stock.location',
                                                'Incoming Transit'),
        'wh_transit_out_loc_id': fields.many2one('stock.location',
                                                 'Outgoing Transit'),
    }

    def create(self, cr, uid, vals, context=None):
        transit_in, transit_out = self._create_transit_locations(
            cr, uid,
            vals.get('company_id'),
            vals.get('reception_steps', ''),
            vals.get('delivery_steps', ''),
            context)
        vals['wh_transit_in_loc_id'] = transit_in
        vals['wh_transit_out_loc_id'] = transit_out
        return super(StockWarehouse, self).create(cr, uid, vals, context)

    def _create_transit_locations(self, cr, uid,
                                  company_id,
                                  reception_steps,
                                  delivery_steps,
                                  context):
        if context is None:
            context = {}
        ctx = context.copy()
        ctx['active_test'] = False
        data_obj = self.pool.get('ir.model.data')
        location_obj = self.pool.get('stock.location')
        try:
            out_id = data_obj.get_object_reference(
                cr, uid, 'stock_route_transit', 'transit_outgoing')[1]
        except:
            out_id = location_obj.create(
                cr, uid,
                {'name': _('Outgoing Transit'),
                 'usage': 'transit',
                 'active': ('transit' in delivery_steps),
                 'company_id': company_id,
                 },
                context=ctx
                )
        in_id = location_obj.create(cr, uid,
                                    {'name': _('Incoming Transit'),
                                     'usage': 'transit',
                                     'active': ('transit' in reception_steps),
                                     'company_id': company_id,
                                     },
                                    context=ctx)
        return in_id, out_id

    def get_routes_dict(self, cr, uid, ids, warehouse, context=None):
        """return a dict of routes. Keys are the possible reception/delivery steps,
        values are tuples of 2 elements:
        1. the name of the route
        2. a list of 0, 1 or 2 tuples of (from_loc, dest_loc, pick_type_id),
           giving the different steps of the route.
        The list is processed by `_get_push_pull_rules`.

        """
        _super = super(StockWarehouse, self)
        routes_dict = _super.get_routes_dict(cr, uid, ids, warehouse, context)
        customer_loc, supplier_loc = self._get_partner_locations(
            cr, uid, ids, context=context)
        warehouse._ensure_transit_loc()
        new_routes = {
            'transit_one_step': (_('Receipt in 1 step from Transit'),
                                 [(warehouse.wh_transit_in_loc_id,
                                   warehouse.lot_stock_id,
                                   warehouse.in_type_id.id
                                   ),
                                  ]
                                 ),
            'transit_two_steps': (_('Receipt in 2 steps from Transit'),
                                  [(warehouse.wh_transit_in_loc_id,
                                    warehouse.wh_input_stock_loc_id,
                                    warehouse.in_type_id.id,
                                    ),
                                   (warehouse.wh_input_stock_loc_id,
                                    warehouse.lot_stock_id,
                                    warehouse.in_type_id.id,
                                    ),
                                   ]
                                  ),
            'transit_three_steps': (_('Receipt in 3 steps from Transit'),
                                    [(warehouse.wh_transit_in_loc_id,
                                      warehouse.wh_input_stock_loc_id,
                                      warehouse.in_type_id.id,
                                      ),
                                     (warehouse.wh_input_stock_loc_id,
                                      warehouse.wh_qc_stock_loc_id,
                                      warehouse.int_type_id.id
                                      ),
                                     (warehouse.wh_qc_stock_loc_id,
                                      warehouse.lot_stock_id,
                                      warehouse.int_type_id.id
                                      ),
                                     ]
                                    ),
            'ship_transit': (_('Ship to Transit'),
                             [(warehouse.lot_stock_id,
                               warehouse.wh_transit_out_loc_id,
                               warehouse.out_type_id.id
                               ),
                              (warehouse.wh_transit_out_loc_id,
                               customer_loc,
                               warehouse.transit_out_type_id.id
                               ),
                              ]
                             ),
            'pick_ship_transit': (_('Pick + Ship + Transit'),
                                  [(warehouse.lot_stock_id,
                                    warehouse.wh_output_stock_loc_id,
                                    warehouse.pick_type_id.id
                                    ),
                                   (warehouse.wh_output_stock_loc_id,
                                    warehouse.wh_transit_out_loc_id,
                                    warehouse.out_type_id.id
                                    ),
                                   (warehouse.wh_transit_out_loc_id,
                                    customer_loc,
                                    warehouse.transit_out_type_id.id
                                    ),
                                   ]
                                  ),
            'pick_pack_ship_transit': (_('Pick + Pack + Ship + Transit'),
                                       [(warehouse.lot_stock_id,
                                         warehouse.wh_pack_stock_loc_id,
                                         warehouse.pick_type_id.id
                                         ),
                                        (warehouse.wh_pack_stock_loc_id,
                                         warehouse.wh_output_stock_loc_id,
                                         warehouse.pack_type_id.id
                                         ),
                                        (warehouse.wh_output_stock_loc_id,
                                         warehouse.wh_transit_out_loc_id,
                                         warehouse.out_type_id.id
                                         ),
                                        (warehouse.wh_transit_out_loc_id,
                                         customer_loc,
                                         warehouse.transit_out_type_id.id
                                         ),
                                        ]
                                       ),
        }
        routes_dict.update(new_routes)
        return routes_dict

    def _ensure_transit_loc(self, cr, uid, ids, context=None):
        """make sure there are output and input transit location set

        they can be missing e.g. for warehouses created before the installation
        of the addon
        """
        for warehouse in self.browse(cr, uid, ids, context=context):
            if not (warehouse.wh_transit_out_loc_id
                    and warehouse.wh_transit_in_loc_id):
                # this can happen for warehouses created before this module was
                # installed
                in_id, out_id = self._create_transit_locations(
                    cr, uid,
                    warehouse.company_id.id,
                    warehouse.reception_steps,
                    warehouse.delivery_steps,
                    context)
                warehouse.write(
                    {'wh_transit_in_loc_id': in_id,
                     'wh_transit_out_loc_id': out_id})

    def switch_location(self, cr, uid, ids,
                        warehouse,
                        new_reception_step=False,
                        new_delivery_step=False,
                        context=None):
        """set unused locations to active=False"""
        warehouse._ensure_transit_loc()
        # incoming transit
        other_wh_ids = self.search(cr, uid,
                                   [('id', '!=', warehouse.id),
                                    ('wh_transit_in_loc_id', '=',
                                     warehouse.wh_transit_in_loc_id.id)
                                    ],
                                   context=context)
        other_wh = self.browse(cr, uid, other_wh_ids, context=context)
        transit_receptions = ['transit' in (new_reception_step or '')] + \
                             ['transit' in other.reception_steps
                              for other in other_wh]
        warehouse.wh_transit_in_loc_id.active = any(transit_receptions)
        # outgoing transit
        other_wh_ids = self.search(cr, uid,
                                   [('id', '!=', warehouse.id),
                                    ('wh_transit_in_loc_id', '=',
                                     warehouse.wh_transit_out_loc_id.id)
                                    ],
                                   context=context)
        other_wh = self.browse(cr, uid, other_wh_ids, context=context)
        transit_deliveries = ['transit' in (new_delivery_step or '')] + \
                             ['transit' in other.delivery_steps
                              for other in other_wh]
        print transit_deliveries
        warehouse.wh_transit_in_loc_id.active = any(transit_deliveries)
        return super(StockWarehouse, self).switch_location(cr, uid, ids,
                                                           warehouse,
                                                           new_reception_step,
                                                           new_delivery_step,
                                                           context)

    def change_route(self, cr, uid, ids,
                     warehouse,
                     new_reception_step=False,
                     new_delivery_step=False,
                     context=None):
        """change input_loc, output_loc
        update active fiels on picking_types

                update location_dest (resp. src) of in (resp. out) picking type
        remove all routes of the WH and recreate them
        """
        super(StockWarehouse, self).change_route(cr, uid, ids,
                                                 warehouse,
                                                 new_reception_step,
                                                 new_delivery_step,
                                                 context)
        if 'transit' not in new_delivery_step and \
          'transit' not in new_reception_step:
            return True
        # due to poor design in base class, we need to redo everything... :-(
        # and add our stuff
        picking_type_obj = self.pool.get('stock.picking.type')
        pull_obj = self.pool.get('procurement.rule')
        push_obj = self.pool.get('stock.location.path')
        route_obj = self.pool.get('stock.location.route')
        new_reception_step = new_reception_step or warehouse.reception_steps
        new_delivery_step = new_delivery_step or warehouse.delivery_steps
        if new_reception_step in ('transit_one_step', 'one_step'):
            input_loc = warehouse.lot_stock_id
        else:
            input_loc = warehouse.wh_input_stock_loc_id
        if new_delivery_step in ('ship_transit', 'ship_only'):
            output_loc = warehouse.lot_stock_id
        else:
            output_loc = warehouse.wh_output_stock_loc_id

        wh = warehouse
        picking_type_writes = [
            (wh.in_type_id.id, {'default_location_dest_id': input_loc.id}),
            (wh.out_type_id.id, {'default_location_src_id': output_loc.id}),
            (wh.pick_type_id.id,
             {'active': new_delivery_step in ('ship_only', 'ship_transit')}),
            (wh.pack_type_id.id,
             {'active': new_delivery_step.startswith('pick_pack_ship')}),
            (wh.transit_in_type_id.id,
             {'active': 'transit' in new_reception_step}),
            (wh.transit_out_type_id.id,
             {'active': 'transit' in new_reception_step}),
        ]
        for pick_type_id, vals in picking_type_writes:
            picking_type_obj.write(
                cr, uid, pick_type_id, vals, context=context)

        # fix active field of the crossdock route
        if new_reception_step.endswith('one_step'):
            cross_dock_active = False
        elif new_delivery_step in ('ship_transit', 'ship_only'):
            cross_dock_active = False
        else:
            cross_dock_active = True
        route_obj.write(cr, uid,
                        warehouse.crossdock_route_id.id,
                        {'active': cross_dock_active},
                        context=context)

        return True

    def create_sequences_and_picking_types(self, cr, uid, warehouse, context=None):
        _super = super(StockWarehouse, self)
        _super.create_sequences_and_picking_types(cr, uid, warehouse, context)
        seq_obj = self.pool.get('ir.sequence')
        picking_type_obj = self.pool.get('stock.picking.type')
        # create new sequences
        in_transit_seq_id = seq_obj.create(cr,
                                           SUPERUSER_ID,
                                           values={'name': warehouse.name + _(' Sequence incoming transit'),
                                                   'prefix': warehouse.code + '/TR-IN/',
                                                   'padding': 5},
                                           context=context)
        out_transit_seq_id = seq_obj.create(cr,
                                            SUPERUSER_ID,
                                            values={'name': warehouse.name + _(' Sequence outgoing transit'),
                                                    'prefix': warehouse.code + '/TR-OUT/',
                                                    'padding': 5},
                                            context=context)
        customer_loc, supplier_loc = self._get_partner_locations(
            cr, uid, warehouse.id, context=context)
        in_transit_type = picking_type_obj.create(cr, uid,
                                                  {'name': _('In Transit'),
                                                   'warehouse_id': warehouse.id,
                                                   'code': 'incoming',
                                                   'sequence_id': in_transit_seq_id,
                                                   'default_location_src_id': supplier_loc.id,
                                                   'default_location_dest_id': warehouse.wh_input_stock_loc_id.id,
                                                   'active': 'transit' in warehouse.reception_steps,
                                                   },
                                                  context=context)
        out_transit_type = picking_type_obj.create(cr, uid,
                                                   {'name': _('Out Transit'),
                                                    'warehouse_id': warehouse.id,
                                                    'code': 'outgoing',
                                                    'sequence_id': in_transit_seq_id,
                                                    'default_location_src_id': warehouse.wh_output_stock_loc_id.id,
                                                    'default_location_dest_id': customer_loc.id,
                                                    'active': 'transit' in warehouse.delivery_steps,
                                                    },
                                                   context=context)
        self.write(cr, uid, warehouse.id,
                   {'transit_in_type_id': in_transit_type,
                    'transit_out_type_id': out_transit_type,
                    },
                   context=context)
<|endoftext|>


<commit_before>"""
Name: Paul Briant
Date: 11/22/16
Class: Introduction to Python
Session07
LAB: HTML Renderer

Description:

"""
# -------------------------------Imports----------------------------------------

# -------------------------------Classes--------------------------------------
class Element:

    tag = 'html'

    def __init__(self, content=None):
        """
        Initializes class attribute content and appends any value not equal to
        none into and empty list.
        """
        self.content = []
        if content:
            self.content.append(content)

    def append(self, content):
        """
        Takes in new content in the form of a string and adds it to list of
        existing content.
        """
        self.content.append(content)

    def render(self, file_out, ind=""):
        """
        Takes in the output file, generates opening and closing tags and
        inserts each individual line of content in between it. All tags and
        content are written to output file.
        """
        file_out.write("<{}>\n".format(self.tag))
        for stuff in self.content:
            file_out.write(stuff+"\n")
        file_out.write("</{}>\n".format(self.tag))

# ==============================================================================

def main():
    """
    Calls functions and produces output.
    """

if __name__ == '__main__':
    main()
<commit_msg>Created Html, Body and P subclasses to represent the functionality of different html elements.<commit_after>"""
Name: Paul Briant
Date: 11/22/16
Class: Introduction to Python
Session07
LAB: HTML Renderer

Description:

"""
# -------------------------------Imports----------------------------------------

# -------------------------------Classes--------------------------------------
class Element:

    tag = 'html'

    def __init__(self, content=None):
        """
        Initializes class attribute content and appends any value not equal to
        none into and empty list.
        """
        self.content = []
        if content:
            self.content.append(content)

    def append(self, content):
        """
        Takes in new content in the form of a string and adds it to list of
        existing content.
        """
        self.content.append(content)

    def render(self, file_out, ind=""):
        """
        Takes in the output file, generates opening and closing tags and
        inserts each individual line of content in between it. All tags and
        content are written to output file.
        """
        file_out.write("<{}>\n".format(self.tag))
        for stuff in self.content:
            file_out.write(stuff+"\n")
        file_out.write("</{}>\n".format(self.tag))

class Html(Element):
        tag = 'html'

class Body(Element):
        tag = 'body'

class P(Element):
        tag = 'p'

# ==============================================================================

def main():
    """
    Calls functions and produces output.
    """

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


<commit_before>import os
import requests
import socket
import json
from django.http import HttpRequest
from django.http import HttpResponse, HttpResponseRedirect
from django.db import connection
from django.contrib.auth.models import User
#function in order to know wich machine/server it's used for POST and GET methods (/api/....)

def api_post(resource, params=None, files=None, json=None):
    host = os.environ.get('IPOL_URL', f'http://{socket.gethostbyname(socket.getfqdn())}')
    response = requests.post(f"{host}{resource}", params=params, data=json, files=files)
    try:
        return response.json()
    except requests.exceptions.Timeout:
        # Maybe set up for a retry, or continue in a retry loop
        return {'status': 'KO'}
    except requests.exceptions.TooManyRedirects:
        # Tell the user their URL was bad and try a different one
        return {'status': 'KO'}
    except requests.exceptions.RequestException as e:
        # catastrophic error. bail.
        raise SystemExit(e)

def user_can_edit_demo(user, demo_id):
    if user.is_staff or user.is_superuser:
        return True
    settings = {'demo_id' : demo_id}
    response_api = api_post("/api/demoinfo/demo_get_editors_list", settings)
    editors_list = response_api.json()
    for editor in editors_list.get('editor_list'):
        if editor.get('mail') == user.email:
            return True
    return False

<commit_msg>[cp2] fixed editor not being able to edit demo<commit_after>import os
import requests
import socket
import json
from django.http import HttpRequest
from django.http import HttpResponse, HttpResponseRedirect
from django.db import connection
from django.contrib.auth.models import User
#function in order to know wich machine/server it's used for POST and GET methods (/api/....)

def api_post(resource, params=None, files=None, json=None):
    host = os.environ.get('IPOL_URL', f'http://{socket.gethostbyname(socket.getfqdn())}')
    response = requests.post(f"{host}{resource}", params=params, data=json, files=files)
    try:
        return response.json()
    except requests.exceptions.Timeout:
        # Maybe set up for a retry, or continue in a retry loop
        return {'status': 'KO'}
    except requests.exceptions.TooManyRedirects:
        # Tell the user their URL was bad and try a different one
        return {'status': 'KO'}
    except requests.exceptions.RequestException as e:
        # catastrophic error. bail.
        raise SystemExit(e)

def user_can_edit_demo(user, demo_id):
    if user.is_staff or user.is_superuser:
        return True
    settings = {'demo_id' : demo_id}
    editors_list = api_post("/api/demoinfo/demo_get_editors_list", settings)
    for editor in editors_list.get('editor_list'):
        if editor.get('mail') == user.email:
            return True
    return False

<|endoftext|>


<commit_before>#!/usr/bin/python

import sys

def tokenize(template):
    class UnclosedSection(Exception):
        pass

    def get(amount=1):
        return template[current:current + amount]

    def look(ahead=0, amount=1):
        idx = current + ahead
        if idx > len(template):
            raise EOFError()

        return template[idx:idx + amount]

    tag_types = {
        '!': 'comment',
        '#': 'section',
        '^': 'inverted section',
        '/': 'end',
        '>': 'partial',
        '=': 'set delimiter?',
        '{': 'no escape?',
        '&': 'no escape'
    }

    current = 0
    open_sections = []
    l_del = '{{'
    r_del = '}}'
    while current < len(template):
        try:
            size = 0
            while look(size, 2) != l_del:
                size += 1
        except EOFError:
            yield ('literal', get(size))
            return

        if size != 0:
            yield ('literal', get(size))

        current += size + 2

        tag_type = tag_types.get(get(), 'variable')
        if tag_type != 'variable':
            current += 1

        size = 1
        while look(size, 2) != r_del:
            size += 1

        tag_key = get(size).strip()
        current += size + 2

        if tag_type == 'no escape?':
            if look(-2, 3) == '}}}':
                tag_type = 'no escape'
                current += 1

        elif tag_type == 'set delimiter?':
            if look(-3) == '=':
                l_del, r_del = tag_key[:-1].split(' ')
                continue

        elif tag_type in ['section', 'inverted section']:
            open_sections.append(tag_key)

        elif tag_type == 'end':
            last_section = open_sections.pop()
            if tag_key != last_section:
                raise UnclosedSection()

        yield (tag_type, tag_key)

    return

if __name__ == '__main__':
    data = sys.argv[1]
    template = sys.argv[2]

    with open(template, 'r') as f:
        template = f.read()

    tokens = tokenize(template)
    for token in tokens:
        print(token)
<commit_msg>Changed sys import to just import argv<commit_after>#!/usr/bin/python

from sys import argv

def tokenize(template):
    class UnclosedSection(Exception):
        pass

    def get(amount=1):
        return template[current:current + amount]

    def look(ahead=0, amount=1):
        idx = current + ahead
        if idx > len(template):
            raise EOFError()

        return template[idx:idx + amount]

    tag_types = {
        '!': 'comment',
        '#': 'section',
        '^': 'inverted section',
        '/': 'end',
        '>': 'partial',
        '=': 'set delimiter?',
        '{': 'no escape?',
        '&': 'no escape'
    }

    current = 0
    open_sections = []
    l_del = '{{'
    r_del = '}}'
    while current < len(template):
        try:
            size = 0
            while look(size, 2) != l_del:
                size += 1
        except EOFError:
            yield ('literal', get(size))
            return

        if size != 0:
            yield ('literal', get(size))

        current += size + 2

        tag_type = tag_types.get(get(), 'variable')
        if tag_type != 'variable':
            current += 1

        size = 1
        while look(size, 2) != r_del:
            size += 1

        tag_key = get(size).strip()
        current += size + 2

        if tag_type == 'no escape?':
            if look(-2, 3) == '}}}':
                tag_type = 'no escape'
                current += 1

        elif tag_type == 'set delimiter?':
            if look(-3) == '=':
                l_del, r_del = tag_key[:-1].split(' ')
                continue

        elif tag_type in ['section', 'inverted section']:
            open_sections.append(tag_key)

        elif tag_type == 'end':
            last_section = open_sections.pop()
            if tag_key != last_section:
                raise UnclosedSection()

        yield (tag_type, tag_key)

    return

if __name__ == '__main__':
    data = argv[1]
    template = argv[2]

    with open(template, 'r') as f:
        template = f.read()

    tokens = tokenize(template)
    for token in tokens:
        print(token)
<|endoftext|>


<commit_before>#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
#
# Copyright 2012 ShopWiki
#
# 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.
#

from datetime import timedelta, datetime
from functools import partial
from threading import Lock
from weakref import WeakValueDictionary
import numbers
import uuid

from tornado import gen
from tornado.gen import Task, Callback, Wait
from tornado.ioloop import IOLoop
from tornado import stack_context

import pika
import simplejson as json

from chu.connection import AsyncRabbitConnectionBase

import logging
logger = logging.getLogger(__name__)

class RPCTimeoutError(Exception):
    '''
    Raised when a call to :meth:`.RPCResponseFuture.wait` times out.
    '''
    pass

class RPCErrorResponse(object):
    pass

class RPCRequest(object):
    '''
    A wrapper object around the exchange, routing_key, and a dictionary
    of parameters that will be json encoded into the body of the rabbit
    message.

    :class:`RPCRequest` is hashable and can therefore be used as a key
    in a dictionary.
    '''

    def __init__(self, exchange, routing_key, params, timeout=None):
        self.exchange = exchange
        self.routing_key = routing_key
        self.params = params
        self.json_params = json.dumps(params, sort_keys=True)
        # if timeout is a number, treat it as seconds
        self.timeout = timeout

    def __hash__(self):
        if not hasattr(self, '_hash'):
            routing_key_hash = hash(self.routing_key)
            params_hash = hash(self.json_params)
            self._hash = hash((routing_key_hash, params_hash))
        return self._hash

class RPCResponseFuture(object):
    '''
    A convenience object for using :class:`AsyncTornadoRPCClient` in a
    non-blocking manner within a Tornado handler.  Calls to
    :meth:`~AsyncTornadoRPCClient.rpc` will return an instance of
    :class:`RPCResponseFuture`.  The user may then call
    :meth:`RPCResponseFuture.get` in order to retrieve the result of the
    RPC.  Using :class:`tornado.gen.Task` is recommended for calling
    :meth:`~RPCResponseFuture.get`.
    '''
    def __init__(self, cid, timeout=None, io_loop=None):
        self.cid = cid
        self.response_received = False
        self.response = None
        self.timeout = timeout
        self.timed_out = False
        self.wait_callback = None
        self.io_loop = io_loop
        if not self.io_loop:
            self.io_loop = IOLoop.instance()

        self.init_time = datetime.now()
        self.get_time = None
        self.timeout_time = None

    @gen.engine
    def get(self, callback, timeout=None):
        '''
        Wait for the RPC associated with this :class:`RPCResponseFuture`
        to return a result.  When the result is received, resolve the
        task by calling the passed in ``callback``.

        :param callback: The callback that will be called with the RPC
            response upon completion of the RPC.  It is recommended that
            this not be passed in directly, but rather that
            :meth:`~.get` be called as a function passed to
            :class:`tornado.gen.Task`.

        :param timeout: The amount of time to wait before raising an
            :exc:`RPCTimeoutError` to indicate that the RPC has timed
            out.  This can be a number or a :class:`timedelta`
            object.  If it is a number, it will be treated as
            seconds.
        '''

        self.get_time = datetime.now()

        if self.response_received:
            logger.info('Response has already been received, return '
                        'the value immediately.')
            callback(self.response)
        else:
            callback = stack_context.wrap(callback)
            if self.timeout and not timeout:
                timeout = self.timeout
            elif not self.timeout and not timeout:
                timeout = timedelta(seconds=6)

            key = uuid.uuid4()
            self.wait_callback = yield gen.Callback(key)
            self.wait_callback = stack_context.wrap(self.wait_callback)

            logger.info('Response has not been received yet.  Adding '
                        'timeout to the io_loop in case the response '
                        'times out.')

            if isinstance(timeout, numbers.Real):
                timeout = timedelta(seconds=timeout)
            self.io_loop.add_timeout(timeout,
                                     stack_context.wrap(self.timeout_callback))

            logger.info('Waiting for the response.')
            yield gen.Wait(key)

            if self.timed_out:
                raise RPCTimeoutError('Future waiting for message with cid: '
                                      '"%s" timed out' % str(self.cid))
            elif self.response_received:
                logger.info('Response received successfully.')
                callback(self.response)
            else:
                raise Exception("Neither timed out nor response received")

    def response_callback(self, response):
        logger.info('Response callback called.')
        self.response_received = True
        self.response = response
        logger.info('Time between init and response: %s'
                    % (datetime.now() - self.init_time))
        if self.wait_callback:
            logger.info('The wait callback has been constructed, '
                        'the user is blocking on the response.')
            self.wait_callback()
        else:
            logger.info('The wait callback has not been constructed, ',
                        'the user has not called get() yet.')

    def timeout_callback(self):
        self.timeout_time = datetime.now()
        if not self.response_received:
            logger.error('The response timeout was called before the'
                         ' response was received. cid: %s.  Difference'
                         ' between init and timeout time was: %s'
                         % (self.cid, self.timeout_time - self.init_time))
            self.timed_out = True
            self.wait_callback()
        else:
            logger.info('The response timeout was called after the '
                        'response was received.')

class RPCResponse(object):
    def __init__(self, channel, method, header, body):
        self.channel = channel
        self.method = method
        self.header = header
        self.body_json = body

    _body = None
    @property
    def body(self):
        if not self._body:
            self._body = json.loads(self.body_json, use_decimal=True)
        return self._body

class AsyncSimpleConsumer(AsyncRabbitConnectionBase):
    @gen.engine
    def consume_queue(self, queue):
        yield gen.Task(self.basic_consume,
                       consumer_callback=self.consume_message,
                       queue=queue)

    def consume_message(self, channel, method, properties, body):
        raise NotImplemented('consume_message should be implemented '
                             'by subclasses of AsyncSimpleConsumer.')

class AsyncTornadoRPCClient(AsyncRabbitConnectionBase):

    """
    Wrap `pika.adapters.tornado_connection.TornadoConnection`
    to provide a simple RPC client powered by ``tornado.gen.engine``
    semantics.

    """

    def __init__(self, *args, **kwargs):
        self.declare_rpc_queue_lock = Lock()

        self.connection_open_callbacks = []
        self.rpc_queue_callbacks = []

        self.rpc_queue = None

        self.futures = WeakValueDictionary()

        super(AsyncTornadoRPCClient, self).__init__(*args, **kwargs)

    def on_closed(self, connection):
        logger.warning('AsyncRabbitClient.on_close: closed!')
        self.rpc_queue = None

    @gen.engine
    def rpc_queue_declare(self, callback, **kwargs):
        if not self.declare_rpc_queue_lock.acquire(False):
            logger.info('RPC Queue is already in the process of '
                        'being declared (declare_rpc_queue_lock '
                        'could not be acquired).')
            callback()
            return

        try:
            self.rpc_queue = yield gen.Task(self.queue_declare,
                                            exclusive=True,
                                            auto_delete=True)
            yield gen.Task(self.basic_consume, queue=self.rpc_queue)

            logger.info('Adding callbacks that are waiting for an RPC '
                        'queue to the tornado queue.')
            while self.rpc_queue_callbacks:
                cb = self.rpc_queue_callbacks.pop()
                self.io_loop.add_callback(cb)
            logger.info('Done adding callbacks.')

        finally:
            self.declare_rpc_queue_lock.release()
            callback()

    @gen.engine
    def ensure_rpc_queue(self, callback):
        logger.info('Ensuring that an RPC queue has been declared.')
        yield Task(self.ensure_connection)
        if self.rpc_queue:
            logger.info('The RPC queue is already open.')
            callback()
        else:
            logger.info('Adding callback to list of callbacks '
                        'waiting for the RPC queue to be open.')
            callback = stack_context.wrap(callback)
            self.rpc_queue_callbacks.append(callback)

            logger.info('Calling rpc_queue_declare().')
            rpc_queue = yield gen.Task(self.rpc_queue_declare)
            logger.info('rpc_queue_declare has been called.')

    @gen.engine
    def rpc(self, rpc_request, properties=None, callback=None):
        '''
        Publish an RPC request.  Returns a :class:`RPCResponseFuture`.

        :param rpc_request: An instance of :class:`RPCRequest`.

        '''

        callback = stack_context.wrap(callback)

        yield Task(self.ensure_connection)
        yield Task(self.ensure_rpc_queue)

        if not properties:
            correlation_id = str(uuid.uuid4())
            properties = pika.BasicProperties(reply_to=self.rpc_queue,
                                              correlation_id=correlation_id)

        logger.info('Publishing RPC request with key: %s' %
                    rpc_request.routing_key)

        self.channel.basic_publish(exchange=rpc_request.exchange,
                                   routing_key=rpc_request.routing_key,
                                   body=rpc_request.json_params,
                                   properties=properties)

        logger.info('Constructing RPC response future with cid: %s' %
                    correlation_id)
        future = RPCResponseFuture(correlation_id,
                                   timeout=rpc_request.timeout,
                                   io_loop=self.io_loop)
        self.futures[correlation_id] = future

        callback(future)

    @gen.engine
    def basic_publish(self, rpc_request, properties=None, callback=None):
        yield Task(self.ensure_connection)
        yield Task(self.ensure_rpc_queue)

        if not properties:
            properties = pika.BasicProperties()

        logger.info('Publishing message request with key: %s' %
                    rpc_request.routing_key)

        self.channel.basic_publish(exchange=rpc_request.exchange,
                                   routing_key=rpc_request.routing_key,
                                   body=rpc_request.json_params,
                                   properties=properties)
        logger.info('channel.basic_publish finished.')
        callback()

    def consume_message(self, channel, method, header, body):
        logger.info('RPC response consumed')
        cid = header.correlation_id

        try:
            future = self.futures.pop(cid)
            response = RPCResponse(channel, method, header, body)
            cb = partial(future.response_callback, response)
            self.io_loop.add_callback(cb)
        except KeyError:
            logger.warning('AsyncRabbitClient.consume_message received an'
                           ' unrecognized correlation_id: %s.  Maybe the'
                           ' RPC took too long and was timed out, or maybe'
                           ' the response was sent more than once.' % cid)
<commit_msg>Make the repr of RPCRequest more meaningful<commit_after>#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
#
# Copyright 2012 ShopWiki
#
# 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.
#

from datetime import timedelta, datetime
from functools import partial
from threading import Lock
from weakref import WeakValueDictionary
import numbers
import uuid

from tornado import gen
from tornado.gen import Task, Callback, Wait
from tornado.ioloop import IOLoop
from tornado import stack_context

import pika
import simplejson as json

from chu.connection import AsyncRabbitConnectionBase

import logging
logger = logging.getLogger(__name__)

class RPCTimeoutError(Exception):
    '''
    Raised when a call to :meth:`.RPCResponseFuture.wait` times out.
    '''
    pass

class RPCErrorResponse(object):
    pass

class RPCRequest(object):
    '''
    A wrapper object around the exchange, routing_key, and a dictionary
    of parameters that will be json encoded into the body of the rabbit
    message.

    :class:`RPCRequest` is hashable and can therefore be used as a key
    in a dictionary.
    '''

    def __init__(self, exchange, routing_key, params, timeout=None):
        self.exchange = exchange
        self.routing_key = routing_key
        self.params = params
        self.json_params = json.dumps(params, sort_keys=True)
        # if timeout is a number, treat it as seconds
        self.timeout = timeout

    def __hash__(self):
        if not hasattr(self, '_hash'):
            routing_key_hash = hash(self.routing_key)
            params_hash = hash(self.json_params)
            self._hash = hash((routing_key_hash, params_hash))
        return self._hash

    def __repr__(self):
        return ("<chu.rpc.RPCRequest:"
                " (exchange: %s, routing_key: %s, params: %s, hash: %s)>" %
                (self.exchange, self.routing_key,
                 self.json_params, hash(self)))

class RPCResponseFuture(object):
    '''
    A convenience object for using :class:`AsyncTornadoRPCClient` in a
    non-blocking manner within a Tornado handler.  Calls to
    :meth:`~AsyncTornadoRPCClient.rpc` will return an instance of
    :class:`RPCResponseFuture`.  The user may then call
    :meth:`RPCResponseFuture.get` in order to retrieve the result of the
    RPC.  Using :class:`tornado.gen.Task` is recommended for calling
    :meth:`~RPCResponseFuture.get`.
    '''
    def __init__(self, cid, timeout=None, io_loop=None):
        self.cid = cid
        self.response_received = False
        self.response = None
        self.timeout = timeout
        self.timed_out = False
        self.wait_callback = None
        self.io_loop = io_loop
        if not self.io_loop:
            self.io_loop = IOLoop.instance()

        self.init_time = datetime.now()
        self.get_time = None
        self.timeout_time = None

    @gen.engine
    def get(self, callback, timeout=None):
        '''
        Wait for the RPC associated with this :class:`RPCResponseFuture`
        to return a result.  When the result is received, resolve the
        task by calling the passed in ``callback``.

        :param callback: The callback that will be called with the RPC
            response upon completion of the RPC.  It is recommended that
            this not be passed in directly, but rather that
            :meth:`~.get` be called as a function passed to
            :class:`tornado.gen.Task`.

        :param timeout: The amount of time to wait before raising an
            :exc:`RPCTimeoutError` to indicate that the RPC has timed
            out.  This can be a number or a :class:`timedelta`
            object.  If it is a number, it will be treated as
            seconds.
        '''

        self.get_time = datetime.now()

        if self.response_received:
            logger.info('Response has already been received, return '
                        'the value immediately.')
            callback(self.response)
        else:
            callback = stack_context.wrap(callback)
            if self.timeout and not timeout:
                timeout = self.timeout
            elif not self.timeout and not timeout:
                timeout = timedelta(seconds=6)

            key = uuid.uuid4()
            self.wait_callback = yield gen.Callback(key)

            logger.info('Response has not been received yet.  Adding '
                        'timeout to the io_loop in case the response '
                        'times out.')

            if isinstance(timeout, numbers.Real):
                timeout = timedelta(seconds=timeout)

            timeout_callback = stack_context.wrap(self.timeout_callback)
            self.io_loop.add_timeout(timeout, timeout_callback)

            logger.info('Waiting for the response.')
            yield gen.Wait(key)

            if self.timed_out:
                raise RPCTimeoutError('Future waiting for message with cid: '
                                      '"%s" timed out' % str(self.cid))
            elif self.response_received:
                logger.info('Response received successfully.')
                callback(self.response)
            else:
                raise Exception("Neither timed out nor response received")

    def response_callback(self, response):
        logger.info('Response callback called.')
        self.response_received = True
        self.response = response
        logger.info('Time between init and response: %s'
                    % (datetime.now() - self.init_time))
        if self.wait_callback:
            logger.info('The wait callback has been constructed, '
                        'the user is blocking on the response.')
            self.wait_callback()
        else:
            logger.info('The wait callback has not been constructed, ',
                        'the user has not called get() yet.')

    def timeout_callback(self):
        self.timeout_time = datetime.now()
        if not self.response_received:
            logger.error('The response timeout was called before the'
                         ' response was received. cid: %s.  Difference'
                         ' between init and timeout time was: %s'
                         % (self.cid, self.timeout_time - self.init_time))
            self.timed_out = True
            self.wait_callback()
        else:
            logger.info('The response timeout was called after the '
                        'response was received.')

class RPCResponse(object):
    def __init__(self, channel, method, header, body):
        self.channel = channel
        self.method = method
        self.header = header
        self.body_json = body

    _body = None
    @property
    def body(self):
        if not self._body:
            self._body = json.loads(self.body_json, use_decimal=True)
        return self._body

class AsyncSimpleConsumer(AsyncRabbitConnectionBase):
    @gen.engine
    def consume_queue(self, queue):
        yield gen.Task(self.basic_consume,
                       consumer_callback=self.consume_message,
                       queue=queue)

    def consume_message(self, channel, method, properties, body):
        raise NotImplemented('consume_message should be implemented '
                             'by subclasses of AsyncSimpleConsumer.')

class AsyncTornadoRPCClient(AsyncRabbitConnectionBase):

    """
    Wrap `pika.adapters.tornado_connection.TornadoConnection`
    to provide a simple RPC client powered by ``tornado.gen.engine``
    semantics.

    """

    def __init__(self, *args, **kwargs):
        self.declare_rpc_queue_lock = Lock()

        self.connection_open_callbacks = []
        self.rpc_queue_callbacks = []

        self.rpc_queue = None

        self.futures = WeakValueDictionary()

        super(AsyncTornadoRPCClient, self).__init__(*args, **kwargs)

    def on_closed(self, connection):
        logger.warning('AsyncRabbitClient.on_close: closed!')
        self.rpc_queue = None

    @gen.engine
    def rpc_queue_declare(self, callback, **kwargs):
        if not self.declare_rpc_queue_lock.acquire(False):
            logger.info('RPC Queue is already in the process of '
                        'being declared (declare_rpc_queue_lock '
                        'could not be acquired).')
            callback()
            return

        try:
            self.rpc_queue = yield gen.Task(self.queue_declare,
                                            exclusive=True,
                                            auto_delete=True)
            yield gen.Task(self.basic_consume, queue=self.rpc_queue)

            logger.info('Adding callbacks that are waiting for an RPC '
                        'queue to the tornado queue.')
            while self.rpc_queue_callbacks:
                cb = self.rpc_queue_callbacks.pop()
                self.io_loop.add_callback(cb)
            logger.info('Done adding callbacks.')

        finally:
            self.declare_rpc_queue_lock.release()
            callback()

    @gen.engine
    def ensure_rpc_queue(self, callback):
        logger.info('Ensuring that an RPC queue has been declared.')
        yield Task(self.ensure_connection)
        if self.rpc_queue:
            logger.info('The RPC queue is already open.')
            callback()
        else:
            logger.info('Adding callback to list of callbacks '
                        'waiting for the RPC queue to be open.')
            callback = stack_context.wrap(callback)
            self.rpc_queue_callbacks.append(callback)

            logger.info('Calling rpc_queue_declare().')
            rpc_queue = yield gen.Task(self.rpc_queue_declare)
            logger.info('rpc_queue_declare has been called.')

    @gen.engine
    def rpc(self, rpc_request, properties=None, callback=None):
        '''
        Publish an RPC request.  Returns a :class:`RPCResponseFuture`.

        :param rpc_request: An instance of :class:`RPCRequest`.

        '''

        callback = stack_context.wrap(callback)

        yield Task(self.ensure_connection)
        yield Task(self.ensure_rpc_queue)

        if not properties:
            correlation_id = str(uuid.uuid4())
            properties = pika.BasicProperties(reply_to=self.rpc_queue,
                                              correlation_id=correlation_id)

        logger.info('Publishing RPC request with key: %s' %
                    rpc_request.routing_key)

        self.channel.basic_publish(exchange=rpc_request.exchange,
                                   routing_key=rpc_request.routing_key,
                                   body=rpc_request.json_params,
                                   properties=properties)

        logger.info('Constructing RPC response future with cid: %s' %
                    correlation_id)
        future = RPCResponseFuture(correlation_id,
                                   timeout=rpc_request.timeout,
                                   io_loop=self.io_loop)
        self.futures[correlation_id] = future

        callback(future)

    @gen.engine
    def basic_publish(self, rpc_request, properties=None, callback=None):
        yield Task(self.ensure_connection)
        yield Task(self.ensure_rpc_queue)

        if not properties:
            properties = pika.BasicProperties()

        logger.info('Publishing message request with key: %s' %
                    rpc_request.routing_key)

        self.channel.basic_publish(exchange=rpc_request.exchange,
                                   routing_key=rpc_request.routing_key,
                                   body=rpc_request.json_params,
                                   properties=properties)
        logger.info('channel.basic_publish finished.')
        callback()

    def consume_message(self, channel, method, header, body):
        logger.info('RPC response consumed')
        cid = header.correlation_id

        try:
            future = self.futures.pop(cid)
            response = RPCResponse(channel, method, header, body)
            cb = partial(future.response_callback, response)
            self.io_loop.add_callback(cb)
        except KeyError:
            logger.warning('AsyncRabbitClient.consume_message received an'
                           ' unrecognized correlation_id: %s.  Maybe the'
                           ' RPC took too long and was timed out, or maybe'
                           ' the response was sent more than once.' % cid)

<|endoftext|>


<commit_before>import random
import sys

import pygame
from pygame.locals import *

FPS = 30
SCREENWIDTH     = 288
SCREENHEIGHT    = 512
PIPEGAPSIZE     = 100 # gap between upper and lower part of pipe
BASEY = SCREENHEIGHT * 0.79
IMAGES, SOUNDS  = {}, {} # image and sound object's dicts

# list of all possible players (tuple of 3 positions of flap)
PLAYERS_LIST = (
    # red bird
    (
        'assets/sprites/redbird-upflap.png',
        'assets/sprites/redbird-midflap.png',
        'assets/sprites/redbird-downflap.png',
    ),
    # blue bird
    (
        'assets/sprites/bluebird-upflap.png',
        'assets/sprites/bluebird-midflap.png',
        'assets/sprites/bluebird-downflap.png',
    ),
    # yellow bird
    (
        'assets/sprites/yellowbird-upflap.png',
        'assets/sprites/yellowbird-midflap.png',
        'assets/sprites/yellowbird-downflap.png',
    ),
)

# list of backgrounds
BACKGROUNDS_LIST = (
    'assets/sprites/background-day.png',
    'assets/sprites/background-night.png',
)

# list of pipes
PIPES_LIST = (
    'assets/sprites/pipe-green.png',
    'assets/sprites/pipe-red.png',
)

def main():
    global SCREEN, FPSCLOCK
    pygame.init()
    FPSCLOCK = pygame.time.Clock()
    SCREEN = pygame.display.set_mode((SCREENWIDTH, SCREENHEIGHT))
    pygame.display.set_caption('Flappy Bird')

    # sprites
    IMAGES['numbers'] = (
        pygame.image.load('assets/sprites/0.png').convert_alpha(),
        pygame.image.load('assets/sprites/1.png').convert_alpha(),
        pygame.image.load('assets/sprites/2.png').convert_alpha(),
        pygame.image.load('assets/sprites/3.png').convert_alpha(),
        pygame.image.load('assets/sprites/4.png').convert_alpha(),
        pygame.image.load('assets/sprites/5.png').convert_alpha(),
        pygame.image.load('assets/sprites/6.png').convert_alpha(),
        pygame.image.load('assets/sprites/7.png').convert_alpha(),
        pygame.image.load('assets/sprites/8.png').convert_alpha(),
        pygame.image.load('assets/sprites/9.png').convert_alpha()
    )

    IMAGES['gameover'] = pygame.image.load('assets/sprites/gameover.png')
    IMAGES['message'] = pygame.image.load('assets/sprites/message.png')
    IMAGES['base'] = pygame.image.load('assets/sprites/base.png')

    # sounds
    SOUNDS['die']    = pygame.mixer.Sound('assets/audio/die.ogg')
    SOUNDS['hit']    = pygame.mixer.Sound('assets/audio/hit.ogg')
    SOUNDS['point']  = pygame.mixer.Sound('assets/audio/point.ogg')
    SOUNDS['swoosh'] = pygame.mixer.Sound('assets/audio/swoosh.ogg')
    SOUNDS['wing']   = pygame.mixer.Sound('assets/audio/wing.ogg')

    while True:
        # sprites
        randBg = random.randint(0, len(BACKGROUNDS_LIST) - 1)
        IMAGES['background'] = pygame.image.load(BACKGROUNDS_LIST[randBg]).convert()

        randPlayer = random.randint(0, len(PLAYERS_LIST) - 1)
        IMAGES['player'] = (
            pygame.image.load(PLAYERS_LIST[randPlayer][0]).convert_alpha(),
            pygame.image.load(PLAYERS_LIST[randPlayer][1]).convert_alpha(),
            pygame.image.load(PLAYERS_LIST[randPlayer][2]).convert_alpha(),
        )

        pipeindex = random.randint(0, len(PIPES_LIST) - 1)
        IMAGES['pipe'] = (
            pygame.transform.rotate(
                pygame.image.load(PIPES_LIST[pipeindex]).convert_alpha(), 180),
            pygame.image.load(PIPES_LIST[pipeindex]).convert_alpha(),
        )

        movementInfo = showWelcomeAnimation()
        crashInfo = mainGame(movementInfo)
        showGameOverScreen(crashInfo)

def showWelcomeAnimation():
    playerIndex = 0
    loopIter = 0

    playerx = int(SCREENWIDTH * 0.2)
    playery = int((SCREENHEIGHT - IMAGES['player'][0].get_height()) / 2)

    messagex = int((SCREENWIDTH - IMAGES['message'].get_width()) / 2)
    messagey = int(SCREENHEIGHT * 0.12)

    basex = 0
    basey = BASEY
    baseShift = IMAGES['base'].get_width() - IMAGES['background'].get_width()

    birdShmValue = 0
    birdShmDir = 1

    while True:
        for event in pygame.event.get():
            if event.type == QUIT or (event.type == KEYDOWN and event.key == K_ESCAPE):
                pygame.quit()
                sys.exit()
            if event.type == KEYDOWN and (event.key == K_SPACE or event.key == K_UP):
                return {
                    'playery': playery + birdShmValue,
                    'basex': basex,
                }

        # adjust playery, playerIndex, basex
        if (loopIter + 1) % 5 == 0:
            playerIndex = (playerIndex + 1) % 3
        loopIter = (loopIter + 1) % 30
        basex = -((-basex + 4) % baseShift)
        birdShmValue, birdShmDir = getBirdShmValue(birdShmValue, birdShmDir)

        # draw sprites
        SCREEN.blit(IMAGES['background'], (0,0))
        SCREEN.blit(IMAGES['player'][playerIndex], (playerx, playery + birdShmValue))
        SCREEN.blit(IMAGES['message'], (messagex, messagey))
        SCREEN.blit(IMAGES['base'], (basex, basey))

        pygame.display.update()
        FPSCLOCK.tick(FPS)

def mainGame(movementInfo):
    score = 0

    playerIndex = 0
    loopIter = 0
    playerx = int(SCREENWIDTH * 0.2)
    playery = movementInfo['playery']

    basex = movementInfo['basex']
    basey = BASEY
    baseShift = IMAGES['base'].get_width() - IMAGES['background'].get_width()

    # get 2 new pipes to add to upperPipes lowerPipes list
    newPipe1 = getRandomPipe()
    newPipe2 = getRandomPipe()

    upperPipes = [
        {'x': SCREENWIDTH + 200, 'y': newPipe1[0]['y']},
        {'x': SCREENWIDTH + 200 + (SCREENWIDTH / 2), 'y': newPipe2[0]['y']},
    ]

    lowerPipes = [
        {'x': SCREENWIDTH + 200, 'y': newPipe1[1]['y']},
        {'x': SCREENWIDTH + 200 + (SCREENWIDTH / 2), 'y': newPipe2[1]['y']},
    ]

    pipeVelX = -4

    # player velocity, max velocity, downward accleration, accleration on flap
    playerVelY    =  -9   # player's velocity along Y, default same as playerFlapped
    playerMaxVelY =  10   # max vel along Y, max descend speed
    playerMinVelY =  -8   # min vel along Y, max ascend speed
    playerAccY    =   1   # players downward accleration
    playerFlapAcc =  -9   # players speed on flapping
    playerFlapped = False # True when player flaps

    while True:
        for event in pygame.event.get():
            if event.type == QUIT or (event.type == KEYDOWN and event.key == K_ESCAPE):
                pygame.quit()
                sys.exit()
            if event.type == KEYDOWN and (event.key == K_SPACE or event.key == K_UP):
                if playery > -2 * IMAGES['player'][0].get_height():
                    playerVelY = playerFlapAcc
                    playerFlapped = True
                    SOUNDS['wing'].play()

        ################################
        ##### CHECK FOR CRASH HERE #####
        ################################
        crashTest = checkCrash({'x': playerx, 'y': playery}, upperPipes, lowerPipes)
        if crashTest[0]:
            return {
                'y': playery,
                'groundCrash': crashTest[1],
                'basex': basex,
                'upperPipes': upperPipes,
                'lowerPipes': lowerPipes,
            }

        # check for score
        playerMidPos = playerx + IMAGES['player'][0].get_width() / 2
        for pipe in upperPipes:
            pipeMidPos = pipe['x'] + IMAGES['pipe'][0].get_width() / 2
            if pipeMidPos <= playerMidPos < pipeMidPos + 4:
                score += 1
                SOUNDS['point'].play()

        # playerIndex basex change
        if (loopIter + 1) % 3 == 0:
            playerIndex = (playerIndex + 1) % 3
        loopIter = (loopIter + 1) % 30
        basex = -((-basex + 100) % baseShift)

        # player's movement
        if playerVelY < playerMaxVelY and not playerFlapped:
            playerVelY += playerAccY
        if playerFlapped:
            playerFlapped = False
        playery += playerVelY

        # move pipes to left
        for uPipe, lPipe in zip(upperPipes, lowerPipes):
            uPipe['x'] += pipeVelX
            lPipe['x'] += pipeVelX

        if 0< upperPipes[0]['x'] < 5:
            newPipe = getRandomPipe()
            upperPipes.append(newPipe[0])
            lowerPipes.append(newPipe[1])

        if upperPipes[0]['x'] < -IMAGES['pipe'][0].get_width():
            upperPipes.pop(0)
            lowerPipes.pop(0)

        # draw sprites
        SCREEN.blit(IMAGES['background'], (0,0))

        for uPipe, lPipe in zip(upperPipes, lowerPipes):
            SCREEN.blit(IMAGES['pipe'][0], (uPipe['x'], uPipe['y']))
            SCREEN.blit(IMAGES['pipe'][1], (lPipe['x'], lPipe['y']))

        SCREEN.blit(IMAGES['base'], (basex, basey))
        # print score so player overlaps the score
        showScore(score)
        SCREEN.blit(IMAGES['player'][playerIndex], (playerx, playery))

        pygame.display.update()
        FPSCLOCK.tick(FPS)

def showGameOverScreen(crashInfo):
    playerx = SCREENWIDTH * 0.2
    playery = crashInfo['y']
    playerHeight = IMAGES['player'][0].get_rect().height
    vel_y = 1

    basex = crashInfo['basex']
    basey = BASEY

    upperPipes, lowerPipes = crashInfo['upperPipes'], crashInfo['lowerPipes']

    # play hit and die sounds
    SOUNDS['hit'].play()
    if not crashInfo['groundCrash']:
        pygame.time.delay(350)
        SOUNDS['die'].play()

    while True:
        for event in pygame.event.get():
            if event.type == QUIT or (event.type == KEYDOWN and event.key == K_ESCAPE):
                pygame.quit()
                sys.exit()
            if event.type == KEYDOWN and (event.key == K_SPACE or event.key == K_UP):
                return

        # player y shift
        if playery + playerHeight < basey:
            playery += vel_y

        # draw sprites
        SCREEN.blit(IMAGES['background'], (0,0))

        for uPipe, lPipe in zip(upperPipes, lowerPipes):
            SCREEN.blit(IMAGES['pipe'][0], (uPipe['x'], uPipe['y']))
            SCREEN.blit(IMAGES['pipe'][1], (lPipe['x'], lPipe['y']))

        SCREEN.blit(IMAGES['base'], (basex, basey))
        SCREEN.blit(IMAGES['player'][1], (playerx,playery))

        pygame.display.update()

def getBirdShmValue(birdShmValue, birdShmDir):
    if abs(birdShmValue) == 8:
        birdShmDir *= -1

    if birdShmDir == 1:
         birdShmValue += 1
    else:
        birdShmValue -= 1
    return birdShmValue, birdShmDir

def getRandomPipe():
    # height of screen - groundheight - where gap can be
    gapY = random.randrange(0, int(BASEY * 0.6 - PIPEGAPSIZE))
    gapY += int(BASEY * 0.2)
    pipeHeight = IMAGES['pipe'][0].get_height()
    pipeX = SCREENWIDTH + 10

    return [
        {'x': pipeX, 'y': gapY - pipeHeight},
        {'x': pipeX, 'y': gapY + PIPEGAPSIZE},
    ]

def showScore(score):
    scoreDigits = [int(x) for x in list(str(score))]
    totalWidth = 0 # total width of all numbers to be printed

    for digit in scoreDigits:
        totalWidth += IMAGES['numbers'][digit].get_width()

    Xoffset = (SCREENWIDTH - totalWidth) / 2

    for digit in scoreDigits:
        SCREEN.blit(IMAGES['numbers'][digit], (Xoffset, SCREENHEIGHT * 0.1))
        Xoffset += IMAGES['numbers'][digit].get_width()

def checkCrash(player, upperPipes, lowerPipes):
    player['w'] = IMAGES['player'][0].get_width()
    player['h'] = IMAGES['player'][0].get_height()
    if player['y'] + player['h'] + 4 >= BASEY:
        return [True, True]
    return [False, False]

if __name__ == '__main__':
    main()
<commit_msg>Add collision with pipes<commit_after>import random
import sys

import pygame
from pygame.locals import *

FPS = 30
SCREENWIDTH     = 288
SCREENHEIGHT    = 512
PIPEGAPSIZE     = 100 # gap between upper and lower part of pipe
BASEY = SCREENHEIGHT * 0.79
IMAGES, SOUNDS  = {}, {} # image and sound object's dicts

# list of all possible players (tuple of 3 positions of flap)
PLAYERS_LIST = (
    # red bird
    (
        'assets/sprites/redbird-upflap.png',
        'assets/sprites/redbird-midflap.png',
        'assets/sprites/redbird-downflap.png',
    ),
    # blue bird
    (
        'assets/sprites/bluebird-upflap.png',
        'assets/sprites/bluebird-midflap.png',
        'assets/sprites/bluebird-downflap.png',
    ),
    # yellow bird
    (
        'assets/sprites/yellowbird-upflap.png',
        'assets/sprites/yellowbird-midflap.png',
        'assets/sprites/yellowbird-downflap.png',
    ),
)

# list of backgrounds
BACKGROUNDS_LIST = (
    'assets/sprites/background-day.png',
    'assets/sprites/background-night.png',
)

# list of pipes
PIPES_LIST = (
    'assets/sprites/pipe-green.png',
    'assets/sprites/pipe-red.png',
)

def main():
    global SCREEN, FPSCLOCK
    pygame.init()
    FPSCLOCK = pygame.time.Clock()
    SCREEN = pygame.display.set_mode((SCREENWIDTH, SCREENHEIGHT))
    pygame.display.set_caption('Flappy Bird')

    # sprites
    IMAGES['numbers'] = (
        pygame.image.load('assets/sprites/0.png').convert_alpha(),
        pygame.image.load('assets/sprites/1.png').convert_alpha(),
        pygame.image.load('assets/sprites/2.png').convert_alpha(),
        pygame.image.load('assets/sprites/3.png').convert_alpha(),
        pygame.image.load('assets/sprites/4.png').convert_alpha(),
        pygame.image.load('assets/sprites/5.png').convert_alpha(),
        pygame.image.load('assets/sprites/6.png').convert_alpha(),
        pygame.image.load('assets/sprites/7.png').convert_alpha(),
        pygame.image.load('assets/sprites/8.png').convert_alpha(),
        pygame.image.load('assets/sprites/9.png').convert_alpha()
    )

    IMAGES['gameover'] = pygame.image.load('assets/sprites/gameover.png')
    IMAGES['message'] = pygame.image.load('assets/sprites/message.png')
    IMAGES['base'] = pygame.image.load('assets/sprites/base.png')

    # sounds
    SOUNDS['die']    = pygame.mixer.Sound('assets/audio/die.ogg')
    SOUNDS['hit']    = pygame.mixer.Sound('assets/audio/hit.ogg')
    SOUNDS['point']  = pygame.mixer.Sound('assets/audio/point.ogg')
    SOUNDS['swoosh'] = pygame.mixer.Sound('assets/audio/swoosh.ogg')
    SOUNDS['wing']   = pygame.mixer.Sound('assets/audio/wing.ogg')

    while True:
        # sprites
        randBg = random.randint(0, len(BACKGROUNDS_LIST) - 1)
        IMAGES['background'] = pygame.image.load(BACKGROUNDS_LIST[randBg]).convert()

        randPlayer = random.randint(0, len(PLAYERS_LIST) - 1)
        IMAGES['player'] = (
            pygame.image.load(PLAYERS_LIST[randPlayer][0]).convert_alpha(),
            pygame.image.load(PLAYERS_LIST[randPlayer][1]).convert_alpha(),
            pygame.image.load(PLAYERS_LIST[randPlayer][2]).convert_alpha(),
        )

        pipeindex = random.randint(0, len(PIPES_LIST) - 1)
        IMAGES['pipe'] = (
            pygame.transform.rotate(
                pygame.image.load(PIPES_LIST[pipeindex]).convert_alpha(), 180),
            pygame.image.load(PIPES_LIST[pipeindex]).convert_alpha(),
        )

        movementInfo = showWelcomeAnimation()
        crashInfo = mainGame(movementInfo)
        showGameOverScreen(crashInfo)

def showWelcomeAnimation():
    playerIndex = 0
    loopIter = 0

    playerx = int(SCREENWIDTH * 0.2)
    playery = int((SCREENHEIGHT - IMAGES['player'][0].get_height()) / 2)

    messagex = int((SCREENWIDTH - IMAGES['message'].get_width()) / 2)
    messagey = int(SCREENHEIGHT * 0.12)

    basex = 0
    basey = BASEY
    baseShift = IMAGES['base'].get_width() - IMAGES['background'].get_width()

    birdShmValue = 0
    birdShmDir = 1

    while True:
        for event in pygame.event.get():
            if event.type == QUIT or (event.type == KEYDOWN and event.key == K_ESCAPE):
                pygame.quit()
                sys.exit()
            if event.type == KEYDOWN and (event.key == K_SPACE or event.key == K_UP):
                return {
                    'playery': playery + birdShmValue,
                    'basex': basex,
                }

        # adjust playery, playerIndex, basex
        if (loopIter + 1) % 5 == 0:
            playerIndex = (playerIndex + 1) % 3
        loopIter = (loopIter + 1) % 30
        basex = -((-basex + 4) % baseShift)
        birdShmValue, birdShmDir = getBirdShmValue(birdShmValue, birdShmDir)

        # draw sprites
        SCREEN.blit(IMAGES['background'], (0,0))
        SCREEN.blit(IMAGES['player'][playerIndex], (playerx, playery + birdShmValue))
        SCREEN.blit(IMAGES['message'], (messagex, messagey))
        SCREEN.blit(IMAGES['base'], (basex, basey))

        pygame.display.update()
        FPSCLOCK.tick(FPS)

def mainGame(movementInfo):
    score = 0

    playerIndex = 0
    loopIter = 0
    playerx = int(SCREENWIDTH * 0.2)
    playery = movementInfo['playery']

    basex = movementInfo['basex']
    basey = BASEY
    baseShift = IMAGES['base'].get_width() - IMAGES['background'].get_width()

    # get 2 new pipes to add to upperPipes lowerPipes list
    newPipe1 = getRandomPipe()
    newPipe2 = getRandomPipe()

    upperPipes = [
        {'x': SCREENWIDTH + 200, 'y': newPipe1[0]['y']},
        {'x': SCREENWIDTH + 200 + (SCREENWIDTH / 2), 'y': newPipe2[0]['y']},
    ]

    lowerPipes = [
        {'x': SCREENWIDTH + 200, 'y': newPipe1[1]['y']},
        {'x': SCREENWIDTH + 200 + (SCREENWIDTH / 2), 'y': newPipe2[1]['y']},
    ]

    pipeVelX = -4

    # player velocity, max velocity, downward accleration, accleration on flap
    playerVelY    =  -9   # player's velocity along Y, default same as playerFlapped
    playerMaxVelY =  10   # max vel along Y, max descend speed
    playerMinVelY =  -8   # min vel along Y, max ascend speed
    playerAccY    =   1   # players downward accleration
    playerFlapAcc =  -9   # players speed on flapping
    playerFlapped = False # True when player flaps

    while True:
        for event in pygame.event.get():
            if event.type == QUIT or (event.type == KEYDOWN and event.key == K_ESCAPE):
                pygame.quit()
                sys.exit()
            if event.type == KEYDOWN and (event.key == K_SPACE or event.key == K_UP):
                if playery > -2 * IMAGES['player'][0].get_height():
                    playerVelY = playerFlapAcc
                    playerFlapped = True
                    SOUNDS['wing'].play()

        # check for crash here
        crashTest = checkCrash({'x': playerx, 'y': playery}, upperPipes, lowerPipes)
        if crashTest[0]:
            return {
                'y': playery,
                'groundCrash': crashTest[1],
                'basex': basex,
                'upperPipes': upperPipes,
                'lowerPipes': lowerPipes,
            }

        # check for score
        playerMidPos = playerx + IMAGES['player'][0].get_width() / 2
        for pipe in upperPipes:
            pipeMidPos = pipe['x'] + IMAGES['pipe'][0].get_width() / 2
            if pipeMidPos <= playerMidPos < pipeMidPos + 4:
                score += 1
                SOUNDS['point'].play()

        # playerIndex basex change
        if (loopIter + 1) % 3 == 0:
            playerIndex = (playerIndex + 1) % 3
        loopIter = (loopIter + 1) % 30
        basex = -((-basex + 100) % baseShift)

        # player's movement
        if playerVelY < playerMaxVelY and not playerFlapped:
            playerVelY += playerAccY
        if playerFlapped:
            playerFlapped = False
        playery += playerVelY

        # move pipes to left
        for uPipe, lPipe in zip(upperPipes, lowerPipes):
            uPipe['x'] += pipeVelX
            lPipe['x'] += pipeVelX

        if 0< upperPipes[0]['x'] < 5:
            newPipe = getRandomPipe()
            upperPipes.append(newPipe[0])
            lowerPipes.append(newPipe[1])

        if upperPipes[0]['x'] < -IMAGES['pipe'][0].get_width():
            upperPipes.pop(0)
            lowerPipes.pop(0)

        # draw sprites
        SCREEN.blit(IMAGES['background'], (0,0))

        for uPipe, lPipe in zip(upperPipes, lowerPipes):
            SCREEN.blit(IMAGES['pipe'][0], (uPipe['x'], uPipe['y']))
            SCREEN.blit(IMAGES['pipe'][1], (lPipe['x'], lPipe['y']))

        SCREEN.blit(IMAGES['base'], (basex, basey))
        # print score so player overlaps the score
        showScore(score)
        SCREEN.blit(IMAGES['player'][playerIndex], (playerx, playery))

        pygame.display.update()
        FPSCLOCK.tick(FPS)

def showGameOverScreen(crashInfo):
    playerx = SCREENWIDTH * 0.2
    playery = crashInfo['y']
    playerHeight = IMAGES['player'][0].get_rect().height
    vel_y = 1

    basex = crashInfo['basex']
    basey = BASEY

    upperPipes, lowerPipes = crashInfo['upperPipes'], crashInfo['lowerPipes']

    # play hit and die sounds
    SOUNDS['hit'].play()
    if not crashInfo['groundCrash']:
        pygame.time.delay(350)
        SOUNDS['die'].play()

    while True:
        for event in pygame.event.get():
            if event.type == QUIT or (event.type == KEYDOWN and event.key == K_ESCAPE):
                pygame.quit()
                sys.exit()
            if event.type == KEYDOWN and (event.key == K_SPACE or event.key == K_UP):
                return

        # player y shift
        if playery + playerHeight < basey:
            playery += vel_y

        # draw sprites
        SCREEN.blit(IMAGES['background'], (0,0))

        for uPipe, lPipe in zip(upperPipes, lowerPipes):
            SCREEN.blit(IMAGES['pipe'][0], (uPipe['x'], uPipe['y']))
            SCREEN.blit(IMAGES['pipe'][1], (lPipe['x'], lPipe['y']))

        SCREEN.blit(IMAGES['base'], (basex, basey))
        SCREEN.blit(IMAGES['player'][1], (playerx,playery))

        pygame.display.update()

def getBirdShmValue(birdShmValue, birdShmDir):
    if abs(birdShmValue) == 8:
        birdShmDir *= -1

    if birdShmDir == 1:
         birdShmValue += 1
    else:
        birdShmValue -= 1
    return birdShmValue, birdShmDir

def getRandomPipe():
    # height of screen - groundheight - where gap can be
    gapY = random.randrange(0, int(BASEY * 0.6 - PIPEGAPSIZE))
    gapY += int(BASEY * 0.2)
    pipeHeight = IMAGES['pipe'][0].get_height()
    pipeX = SCREENWIDTH + 10

    return [
        {'x': pipeX, 'y': gapY - pipeHeight},
        {'x': pipeX, 'y': gapY + PIPEGAPSIZE},
    ]

def showScore(score):
    scoreDigits = [int(x) for x in list(str(score))]
    totalWidth = 0 # total width of all numbers to be printed

    for digit in scoreDigits:
        totalWidth += IMAGES['numbers'][digit].get_width()

    Xoffset = (SCREENWIDTH - totalWidth) / 2

    for digit in scoreDigits:
        SCREEN.blit(IMAGES['numbers'][digit], (Xoffset, SCREENHEIGHT * 0.1))
        Xoffset += IMAGES['numbers'][digit].get_width()

def checkCrash(player, upperPipes, lowerPipes):
    player['w'] = IMAGES['player'][0].get_width()
    player['h'] = IMAGES['player'][0].get_height()
    if player['y'] + player['h'] + 4 >= BASEY:
        return [True, True]
    else:
        playerRect = pygame.Rect(player['x'], player['y'],
                      player['w'], player['h'])
        pipeW = IMAGES['pipe'][0].get_width()
        pipeH = IMAGES['pipe'][0].get_height()

        for uPipe, lPipe in zip(upperPipes, lowerPipes):
            uPipe = (uPipe['x'], uPipe['y'], pipeW, pipeH)
            lPipe = (lPipe['x'], lPipe['y'], pipeW, pipeH)
            if playerRect.colliderect(uPipe) or playerRect.colliderect(lPipe):
                return [True, False]

    return [False, False]

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