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

from datetime import datetime, timedelta

from odoo import api, fields, models, _
from odoo.tools import DEFAULT_SERVER_DATETIME_FORMAT, float_compare
from odoo.exceptions import UserError

class SaleOrder(models.Model):
    _inherit = "sale.order"

    @api.model
    def _default_warehouse_id(self):
        company = self.env.user.company_id.id
        warehouse_ids = self.env['stock.warehouse'].search([('company_id', '=', company)], limit=1)
        return warehouse_ids

    incoterm = fields.Many2one(
        'stock.incoterms', 'Incoterms',
        help="International Commercial Terms are a series of predefined commercial terms used in international transactions.")
    picking_policy = fields.Selection([
        ('direct', 'Deliver each product when available'),
        ('one', 'Deliver all products at once')],
        string='Shipping Policy', required=True, readonly=True, default='direct',
        states={'draft': [('readonly', False)], 'sent': [('readonly', False)]})
    warehouse_id = fields.Many2one(
        'stock.warehouse', string='Warehouse',
        required=True, readonly=True, states={'draft': [('readonly', False)], 'sent': [('readonly', False)]},
        default=_default_warehouse_id)
    picking_ids = fields.Many2many('stock.picking', compute='_compute_picking_ids', string='Picking associated to this sale')
    delivery_count = fields.Integer(string='Delivery Orders', compute='_compute_picking_ids')

    @api.multi
    @api.depends('procurement_group_id')
    def _compute_picking_ids(self):
        for order in self:
            order.picking_ids = self.env['stock.picking'].search([('group_id', '=', order.procurement_group_id.id)]) if order.procurement_group_id else []
            order.delivery_count = len(order.picking_ids)

    @api.onchange('warehouse_id')
    def _onchange_warehouse_id(self):
        if self.warehouse_id.company_id:
            self.company_id = self.warehouse_id.company_id.id

    @api.multi
    def action_view_delivery(self):
        '''
        This function returns an action that display existing delivery orders
        of given sales order ids. It can either be a in a list or in a form
        view, if there is only one delivery order to show.
        '''
        action = self.env.ref('stock.action_picking_tree_all').read()[0]

        pickings = self.mapped('picking_ids')
        if len(pickings) > 1:
            action['domain'] = [('id', 'in', pickings.ids)]
        elif pickings:
            action['views'] = [(self.env.ref('stock.view_picking_form').id, 'form')]
            action['res_id'] = pickings.id
        return action

    @api.multi
    def action_cancel(self):
        self.order_line.mapped('procurement_ids').cancel()
        return super(SaleOrder, self).action_cancel()

    @api.multi
    def _prepare_invoice(self):
        invoice_vals = super(SaleOrder, self)._prepare_invoice()
        invoice_vals['incoterms_id'] = self.incoterm.id or False
        return invoice_vals

    def _prepare_procurement_group(self):
        res = super(SaleOrder, self)._prepare_procurement_group()
        res.update({'move_type': self.picking_policy, 'partner_id': self.partner_shipping_id.id})
        return res

    @api.model
    def _get_customer_lead(self, product_tmpl_id):
        super(SaleOrder, self)._get_customer_lead(product_tmpl_id)
        return product_tmpl_id.sale_delay

class SaleOrderLine(models.Model):
    _inherit = 'sale.order.line'

    product_packaging = fields.Many2one('product.packaging', string='Packaging', default=False)
    route_id = fields.Many2one('stock.location.route', string='Route', domain=[('sale_selectable', '=', True)])
    product_tmpl_id = fields.Many2one('product.template', related='product_id.product_tmpl_id', string='Product Template', readonly=True)

    @api.depends('order_id.state')
    def _compute_invoice_status(self):
        super(SaleOrderLine, self)._compute_invoice_status()
        for line in self:
            # We handle the following specific situation: a physical product is partially delivered,
            # but we would like to set its invoice status to 'Fully Invoiced'. The use case is for
            # products sold by weight, where the delivered quantity rarely matches exactly the
            # quantity ordered.
            if line.order_id.state == 'done'\
                    and line.invoice_status == 'no'\
                    and line.product_id.type in ['consu', 'product']\
                    and line.product_id.invoice_policy == 'delivery'\
                    and line.procurement_ids.mapped('move_ids')\
                    and all(move.state in ['done', 'cancel'] for move in line.procurement_ids.mapped('move_ids')):
                line.invoice_status = 'invoiced'

    @api.multi
    @api.depends('product_id')
    def _compute_qty_delivered_updateable(self):
        for line in self:
            if line.product_id.type not in ('consu', 'product'):
                super(SaleOrderLine, line)._compute_qty_delivered_updateable()
            else:
                line.qty_delivered_updateable = False

    @api.onchange('product_id')
    def _onchange_product_id_set_customer_lead(self):
        self.customer_lead = self.product_id.sale_delay

    @api.onchange('product_packaging')
    def _onchange_product_packaging(self):
        if self.product_packaging:
            return self._check_package()

    @api.onchange('product_id')
    def _onchange_product_id_uom_check_availability(self):
        if not self.product_uom or (self.product_id.uom_id.category_id.id != self.product_uom.category_id.id):
            self.product_uom = self.product_id.uom_id
        self._onchange_product_id_check_availability()

    @api.onchange('product_uom_qty', 'product_uom', 'route_id')
    def _onchange_product_id_check_availability(self):
        if not self.product_id or not self.product_uom_qty or not self.product_uom:
            self.product_packaging = False
            return {}
        if self.product_id.type == 'product':
            precision = self.env['decimal.precision'].precision_get('Product Unit of Measure')
            product_qty = self.product_uom._compute_quantity(self.product_uom_qty, self.product_id.uom_id)
            if float_compare(self.product_id.virtual_available, product_qty, precision_digits=precision) == -1:
                is_available = self._check_routing()
                if not is_available:
                    warning_mess = {
                        'title': _('Not enough inventory!'),
                        'message' : _('You plan to sell %s %s but you only have %s %s available!\nThe stock on hand is %s %s.') % \
                            (self.product_uom_qty, self.product_uom.name, self.product_id.virtual_available, self.product_id.uom_id.name, self.product_id.qty_available, self.product_id.uom_id.name)
                    }
                    return {'warning': warning_mess}
        return {}

    @api.onchange('product_uom_qty')
    def _onchange_product_uom_qty(self):
        if self.state == 'sale' and self.product_id.type in ['product', 'consu'] and self.product_uom_qty < self._origin.product_uom_qty:
            warning_mess = {
                'title': _('Ordered quantity decreased!'),
                'message' : _('You are decreasing the ordered quantity! Do not forget to manually update the delivery order if needed.'),
            }
            return {'warning': warning_mess}
        return {}

    @api.multi
    def _prepare_order_line_procurement(self, group_id=False):
        vals = super(SaleOrderLine, self)._prepare_order_line_procurement(group_id=group_id)
        date_planned = datetime.strptime(self.order_id.date_order, DEFAULT_SERVER_DATETIME_FORMAT)\
            + timedelta(days=self.customer_lead or 0.0) - timedelta(days=self.order_id.company_id.security_lead)
        vals.update({
            'date_planned': date_planned.strftime(DEFAULT_SERVER_DATETIME_FORMAT),
            'location_id': self.order_id.partner_shipping_id.property_stock_customer.id,
            'route_ids': self.route_id and [(4, self.route_id.id)] or [],
            'warehouse_id': self.order_id.warehouse_id and self.order_id.warehouse_id.id or False,
            'partner_dest_id': self.order_id.partner_shipping_id.id,
            'sale_line_id': self.id,
        })
        return vals

    @api.multi
    def _get_delivered_qty(self):
        """Computes the delivered quantity on sale order lines, based on done stock moves related to its procurements
        """
        self.ensure_one()
        super(SaleOrderLine, self)._get_delivered_qty()
        qty = 0.0
        for move in self.procurement_ids.mapped('move_ids').filtered(lambda r: r.state == 'done' and not r.scrapped):
            if move.location_dest_id.usage == "customer":
                if not move.origin_returned_move_id:
                    qty += move.product_uom._compute_quantity(move.product_uom_qty, self.product_uom)
            elif move.location_dest_id.usage == "internal" and move.to_refund_so:
                qty -= move.product_uom._compute_quantity(move.product_uom_qty, self.product_uom)
        return qty

    @api.multi
    def _check_package(self):
        default_uom = self.product_id.uom_id
        pack = self.product_packaging
        qty = self.product_uom_qty
        q = default_uom._compute_quantity(pack.qty, self.product_uom)
        if qty and q and (qty % q):
            newqty = qty - (qty % q) + q
            return {
                'warning': {
                    'title': _('Warning'),
                    'message': _("This product is packaged by %.2f %s. You should sell %.2f %s.") % (pack.qty, default_uom.name, newqty, self.product_uom.name),
                },
            }
        return {}

    def _check_routing(self):
        """ Verify the route of the product based on the warehouse
            return True if the product availibility in stock does not need to be verified,
            which is the case in MTO, Cross-Dock or Drop-Shipping
        """
        is_available = False
        product_routes = self.route_id or (self.product_id.route_ids + self.product_id.categ_id.total_route_ids)

        # Check MTO
        wh_mto_route = self.order_id.warehouse_id.mto_pull_id.route_id
        if wh_mto_route and wh_mto_route <= product_routes:
            is_available = True
        else:
            mto_route = False
            try:
                mto_route = self.env['stock.warehouse']._get_mto_route()
            except UserError:
                # if route MTO not found in ir_model_data, we treat the product as in MTS
                pass
            if mto_route and mto_route in product_routes:
                is_available = True

        # Check Drop-Shipping
        if not is_available:
            for pull_rule in product_routes.mapped('pull_ids'):
                if pull_rule.picking_type_id.sudo().default_location_src_id.usage == 'supplier' and\
                        pull_rule.picking_type_id.sudo().default_location_dest_id.usage == 'customer':
                    is_available = True
                    break

        return is_available
<commit_msg>[FIX] sale_stock: return a delivered product with a non internal location<commit_after># -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.

from datetime import datetime, timedelta

from odoo import api, fields, models, _
from odoo.tools import DEFAULT_SERVER_DATETIME_FORMAT, float_compare
from odoo.exceptions import UserError

class SaleOrder(models.Model):
    _inherit = "sale.order"

    @api.model
    def _default_warehouse_id(self):
        company = self.env.user.company_id.id
        warehouse_ids = self.env['stock.warehouse'].search([('company_id', '=', company)], limit=1)
        return warehouse_ids

    incoterm = fields.Many2one(
        'stock.incoterms', 'Incoterms',
        help="International Commercial Terms are a series of predefined commercial terms used in international transactions.")
    picking_policy = fields.Selection([
        ('direct', 'Deliver each product when available'),
        ('one', 'Deliver all products at once')],
        string='Shipping Policy', required=True, readonly=True, default='direct',
        states={'draft': [('readonly', False)], 'sent': [('readonly', False)]})
    warehouse_id = fields.Many2one(
        'stock.warehouse', string='Warehouse',
        required=True, readonly=True, states={'draft': [('readonly', False)], 'sent': [('readonly', False)]},
        default=_default_warehouse_id)
    picking_ids = fields.Many2many('stock.picking', compute='_compute_picking_ids', string='Picking associated to this sale')
    delivery_count = fields.Integer(string='Delivery Orders', compute='_compute_picking_ids')

    @api.multi
    @api.depends('procurement_group_id')
    def _compute_picking_ids(self):
        for order in self:
            order.picking_ids = self.env['stock.picking'].search([('group_id', '=', order.procurement_group_id.id)]) if order.procurement_group_id else []
            order.delivery_count = len(order.picking_ids)

    @api.onchange('warehouse_id')
    def _onchange_warehouse_id(self):
        if self.warehouse_id.company_id:
            self.company_id = self.warehouse_id.company_id.id

    @api.multi
    def action_view_delivery(self):
        '''
        This function returns an action that display existing delivery orders
        of given sales order ids. It can either be a in a list or in a form
        view, if there is only one delivery order to show.
        '''
        action = self.env.ref('stock.action_picking_tree_all').read()[0]

        pickings = self.mapped('picking_ids')
        if len(pickings) > 1:
            action['domain'] = [('id', 'in', pickings.ids)]
        elif pickings:
            action['views'] = [(self.env.ref('stock.view_picking_form').id, 'form')]
            action['res_id'] = pickings.id
        return action

    @api.multi
    def action_cancel(self):
        self.order_line.mapped('procurement_ids').cancel()
        return super(SaleOrder, self).action_cancel()

    @api.multi
    def _prepare_invoice(self):
        invoice_vals = super(SaleOrder, self)._prepare_invoice()
        invoice_vals['incoterms_id'] = self.incoterm.id or False
        return invoice_vals

    def _prepare_procurement_group(self):
        res = super(SaleOrder, self)._prepare_procurement_group()
        res.update({'move_type': self.picking_policy, 'partner_id': self.partner_shipping_id.id})
        return res

    @api.model
    def _get_customer_lead(self, product_tmpl_id):
        super(SaleOrder, self)._get_customer_lead(product_tmpl_id)
        return product_tmpl_id.sale_delay

class SaleOrderLine(models.Model):
    _inherit = 'sale.order.line'

    product_packaging = fields.Many2one('product.packaging', string='Packaging', default=False)
    route_id = fields.Many2one('stock.location.route', string='Route', domain=[('sale_selectable', '=', True)])
    product_tmpl_id = fields.Many2one('product.template', related='product_id.product_tmpl_id', string='Product Template', readonly=True)

    @api.depends('order_id.state')
    def _compute_invoice_status(self):
        super(SaleOrderLine, self)._compute_invoice_status()
        for line in self:
            # We handle the following specific situation: a physical product is partially delivered,
            # but we would like to set its invoice status to 'Fully Invoiced'. The use case is for
            # products sold by weight, where the delivered quantity rarely matches exactly the
            # quantity ordered.
            if line.order_id.state == 'done'\
                    and line.invoice_status == 'no'\
                    and line.product_id.type in ['consu', 'product']\
                    and line.product_id.invoice_policy == 'delivery'\
                    and line.procurement_ids.mapped('move_ids')\
                    and all(move.state in ['done', 'cancel'] for move in line.procurement_ids.mapped('move_ids')):
                line.invoice_status = 'invoiced'

    @api.multi
    @api.depends('product_id')
    def _compute_qty_delivered_updateable(self):
        for line in self:
            if line.product_id.type not in ('consu', 'product'):
                super(SaleOrderLine, line)._compute_qty_delivered_updateable()
            else:
                line.qty_delivered_updateable = False

    @api.onchange('product_id')
    def _onchange_product_id_set_customer_lead(self):
        self.customer_lead = self.product_id.sale_delay

    @api.onchange('product_packaging')
    def _onchange_product_packaging(self):
        if self.product_packaging:
            return self._check_package()

    @api.onchange('product_id')
    def _onchange_product_id_uom_check_availability(self):
        if not self.product_uom or (self.product_id.uom_id.category_id.id != self.product_uom.category_id.id):
            self.product_uom = self.product_id.uom_id
        self._onchange_product_id_check_availability()

    @api.onchange('product_uom_qty', 'product_uom', 'route_id')
    def _onchange_product_id_check_availability(self):
        if not self.product_id or not self.product_uom_qty or not self.product_uom:
            self.product_packaging = False
            return {}
        if self.product_id.type == 'product':
            precision = self.env['decimal.precision'].precision_get('Product Unit of Measure')
            product_qty = self.product_uom._compute_quantity(self.product_uom_qty, self.product_id.uom_id)
            if float_compare(self.product_id.virtual_available, product_qty, precision_digits=precision) == -1:
                is_available = self._check_routing()
                if not is_available:
                    warning_mess = {
                        'title': _('Not enough inventory!'),
                        'message' : _('You plan to sell %s %s but you only have %s %s available!\nThe stock on hand is %s %s.') % \
                            (self.product_uom_qty, self.product_uom.name, self.product_id.virtual_available, self.product_id.uom_id.name, self.product_id.qty_available, self.product_id.uom_id.name)
                    }
                    return {'warning': warning_mess}
        return {}

    @api.onchange('product_uom_qty')
    def _onchange_product_uom_qty(self):
        if self.state == 'sale' and self.product_id.type in ['product', 'consu'] and self.product_uom_qty < self._origin.product_uom_qty:
            warning_mess = {
                'title': _('Ordered quantity decreased!'),
                'message' : _('You are decreasing the ordered quantity! Do not forget to manually update the delivery order if needed.'),
            }
            return {'warning': warning_mess}
        return {}

    @api.multi
    def _prepare_order_line_procurement(self, group_id=False):
        vals = super(SaleOrderLine, self)._prepare_order_line_procurement(group_id=group_id)
        date_planned = datetime.strptime(self.order_id.date_order, DEFAULT_SERVER_DATETIME_FORMAT)\
            + timedelta(days=self.customer_lead or 0.0) - timedelta(days=self.order_id.company_id.security_lead)
        vals.update({
            'date_planned': date_planned.strftime(DEFAULT_SERVER_DATETIME_FORMAT),
            'location_id': self.order_id.partner_shipping_id.property_stock_customer.id,
            'route_ids': self.route_id and [(4, self.route_id.id)] or [],
            'warehouse_id': self.order_id.warehouse_id and self.order_id.warehouse_id.id or False,
            'partner_dest_id': self.order_id.partner_shipping_id.id,
            'sale_line_id': self.id,
        })
        return vals

    @api.multi
    def _get_delivered_qty(self):
        """Computes the delivered quantity on sale order lines, based on done stock moves related to its procurements
        """
        self.ensure_one()
        super(SaleOrderLine, self)._get_delivered_qty()
        qty = 0.0
        for move in self.procurement_ids.mapped('move_ids').filtered(lambda r: r.state == 'done' and not r.scrapped):
            if move.location_dest_id.usage == "customer":
                if not move.origin_returned_move_id:
                    qty += move.product_uom._compute_quantity(move.product_uom_qty, self.product_uom)
            elif move.location_dest_id.usage != "customer" and move.to_refund_so:
                qty -= move.product_uom._compute_quantity(move.product_uom_qty, self.product_uom)
        return qty

    @api.multi
    def _check_package(self):
        default_uom = self.product_id.uom_id
        pack = self.product_packaging
        qty = self.product_uom_qty
        q = default_uom._compute_quantity(pack.qty, self.product_uom)
        if qty and q and (qty % q):
            newqty = qty - (qty % q) + q
            return {
                'warning': {
                    'title': _('Warning'),
                    'message': _("This product is packaged by %.2f %s. You should sell %.2f %s.") % (pack.qty, default_uom.name, newqty, self.product_uom.name),
                },
            }
        return {}

    def _check_routing(self):
        """ Verify the route of the product based on the warehouse
            return True if the product availibility in stock does not need to be verified,
            which is the case in MTO, Cross-Dock or Drop-Shipping
        """
        is_available = False
        product_routes = self.route_id or (self.product_id.route_ids + self.product_id.categ_id.total_route_ids)

        # Check MTO
        wh_mto_route = self.order_id.warehouse_id.mto_pull_id.route_id
        if wh_mto_route and wh_mto_route <= product_routes:
            is_available = True
        else:
            mto_route = False
            try:
                mto_route = self.env['stock.warehouse']._get_mto_route()
            except UserError:
                # if route MTO not found in ir_model_data, we treat the product as in MTS
                pass
            if mto_route and mto_route in product_routes:
                is_available = True

        # Check Drop-Shipping
        if not is_available:
            for pull_rule in product_routes.mapped('pull_ids'):
                if pull_rule.picking_type_id.sudo().default_location_src_id.usage == 'supplier' and\
                        pull_rule.picking_type_id.sudo().default_location_dest_id.usage == 'customer':
                    is_available = True
                    break

        return is_available
<|endoftext|>


<commit_before>#!/usr/bin/env python
#
#   This tool trades bitcoin on the CampBX platform with a focus on Flask.
#   Copyright (C) 2013 Christopher Jastram
#
#   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/>.
#

import unirest
from flask import Flask
from flask import render_template
app = Flask(__name__)

class CampBX:
    login = "X"
    password = "X"
    headers = {
        'Accept': 'application/json',
        'Content-Type': 'application/json; charset=UTF-8'
    }
    def tick(self):
        response = unirest.post("http://campbx.com/api/xticker.php", self.headers, {})
        return { 'bid': float(response.body["Best Bid"]), 'ask': float(response.body["Best Ask"]) }
    def buy(self, qty, price):
        params = {
            'user': self.login,
            'pass': self.password,
            'TradeMode': 'QuickBuy',
            'Quantity': qty,
            'Price': price
        }
        url = "https://CampBX.com/api/tradeenter.php"
        response = unirest.post(url, self.headers, params)
        if "Error" in response.body:
            raise Exception(response.body["Error"])
        print response.body

@app.route("/")
def hello():
    trader = CampBX()
    tick = trader.tick()

    floor = 150
    ceiling = tick["ask"]
    interval = 5
    spread = 7
    ideal_pairs = []

    # No continuous variable, need to line up
    # the order grid in a predictable way.
    floor = floor - (floor % 7)

    bid = floor
    while bid < ceiling:
        pair = {
            "bid": bid,
            "ask": (bid+spread)
        }
        ideal_pairs.append(pair)
        bid = bid + interval
    print trader.buy("0.01", "147")
    print ideal_pairs

    return render_template('index.html', bid=tick["bid"], ask=tick["ask"])

if __name__ == "__main__":
    app.debug = True
    app.run()
<commit_msg>Fleshing out OO framework, order handling and tracking<commit_after>#!/usr/bin/env python
#
#   This tool trades bitcoin on the CampBX platform with a focus on Flask.
#   Copyright (C) 2013 Christopher Jastram
#
#   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/>.
#

import math
import unirest
from flask import Flask
from flask import render_template
app = Flask(__name__)

class Orders(list):
    order_book_filename = "order-book.yaml"
    order_book = []

    def __init__(self):
        orders.readOrderBook()
        filled = orders.mapExchangeOrders(self.getOrders())

    def readOrderBook(self):
        self.order_book = []
        try:
            f = file(self.order_book_filename, "r")
            self.order_book = yaml.load(f)
            f.close()
        except IOError:
            print "--> Failed to load order book, starting anew"

    def mapExchangeOrders(self, orders):
        recorded = []
        for local in self.order_book:
            bid_exchange_id = local["bid"]["exchange_id"]
            ask_exchange_id = local["ask"]["exchange_id"]
            if bid_exchange_id or ask_exchange_id:
                if bid_exchange_id: recorded.append(bid_exchange_id)
                if ask_exchange_id: recorded.append(ask_exchange_id)

        # If recorded and active, order is working
        # If recorded but not active, order was filled
        # If active but not recorded, order is probably a user order, should ignore
        # If neither active nor recorded, WTF?

        active = [remote["id"] for remote in orders]
        working = [id for id in active if id in recorded]
        filled = [id for id in recorded if id not in active]
        user = [id for id in active if id not in recorded]
        wtf = [id for id in active if id not in working and id not in filled]
        for id in user:
            print "--> User order: %s" % id
        for id in wtf:
            print "--> UNKNOWN ORDER: %s" % id

        #print "RECORDED"
        #print recorded
        #print "ACTIVE"
        #print active
        #print "ALL"
        #print all
        #print "WORKING"
        #print working
        #print "FILLED"
        #print filled
        #print "USER"
        #print user
        #print "DUDE"
        #print wtf

        ### Reset statuses
        for local in self.order_book:
            for side in ["bid", "ask"]:
                id = local[side]["exchange_id"]
                local[side]["status"] = None
                if id in working: local[side]["status"] = "WORKING"
                if id in filled: local[side]["status"] = "FILLED"

    def filledBidsUnpaired(self):
        filled = []
        for local in self.order_book:
            if local["bid"]["status"] == "FILLED" and local["ask"]["exchange_id"] is None:
                filled.append(local["bid"]["exchange_id"])
        return filled

    def details(self, id):
        for local in self.order_book:
            for side in ["bid", "ask"]:
                if local[side]["exchange_id"] == id:
                    return local[side]

    def bids(self):
        pass
    def asks(self):
        pass
    def add(self, side, amount, price, exchange_id, exchange_timestamp):
        self.append({"side": side,
                     "price": price,
                     "amount": amount,
                     "exchange_id": exchange_id,
                     "exchange_timestamp": exchange_timestamp,
                     })

class Algorithm:
    trader = None

    def __init__(self, trader):
        self.trader = trader

    def run(self):
        orders = Orders()

        ### Clear order pairs
        for local in orders.order_book:
            if local["bid"]["status"] == "FILLED" and local["ask"]["status"] == "FILLED":
                print "--> UNIMPLEMENTED: need to clear order!"

        ### Place asks for filled bids
        for id in orders.filledBidsUnpaired():
            print "--> Need to place ask orders for %s" % id

        ### Place new bids

        ### Cancel low orders

        ### Adjust existing orders

        print orders
        # {u'Success': u'1921853'}

class CampBX:
    login = "X"
    password = "X"
    headers = {
        'Accept': 'application/json',
        'Content-Type': 'application/json; charset=UTF-8'
    }
    def tick(self):
        response = unirest.post("http://campbx.com/api/xticker.php") #, self.headers, {})
        return { 'bid': float(response.body["Best Bid"]), 'ask': float(response.body["Best Ask"]) }
    def bid(self, qty, price):
        params = {
            'user': self.login,
            'pass': self.password,
            'TradeMode': 'QuickBuy',
            'Quantity': qty,
            'Price': price
        }
        url = "https://campbx.com/api/tradeenter.php"
        #args = ""
        #for key, value in params.iteritems():
            #if len(args): args = args + "&"
            #args = args + "%s=%s" % (key, value)
        #url = url + "?" + args
        #response = unirest.post(url, headers=self.headers, params={})
        #if "Error" in response.body:
            #raise Exception("Bitcoin exchange API error: %s" % response.body["Error"])
        # {u'Success': u'1921853'}
        print response.body

    def getOrders(self):
        url = "https://campbx.com/api/myorders.php?user=%s&pass=%s" % (self.login, self.password)
        response = unirest.post(url, headers=self.headers, params={})
        if "Error" in response.body:
            raise Exception("Bitcoin exchange API error: %s" % response.body["Error"])

        orders = []
        for order_type, exchange_orders in response.body.iteritems():
            order_type = order_type.lower()
            for exchange_order in exchange_orders:
                if not "Price" in exchange_order: continue
                orders.append({
                    "id": exchange_order["Order ID"],
                    "side": order_type.lower(),
                    "price": exchange_order["Price"],
                    "amount": exchange_order["Quantity"],
                    "timestamp": exchange_order["Order Entered"],
                    })
        return orders

@app.route("/")
def hello():
    trader = CampBX()

    tick = trader.tick()
    ceiling = tick["ask"]
    floor = math.floor(ceiling * 0.80)
    interval = 5
    spread = 7
    ideal_pairs = []

    # No continuous variable, need to line up
    # the order grid in a predictable way.
    floor = floor - (floor % 7)

    bid = floor
    while bid < ceiling:
        pair = {
            "bid": bid,
            "ask": (bid+spread)
        }
        ideal_pairs.append(pair)
        bid = bid + interval
    #print trader.buy("0.01", "147")
    #print ideal_pairs

    algo = Algorithm(trader)
    print algo.run()

    return render_template('index.html', bid=tick["bid"], ask=tick["ask"])

if __name__ == "__main__":
    app.debug = True
    app.run()
<|endoftext|>


<commit_before>#!/usr/bin/env python

import functools
import optparse
import socket
import thread
import threading
import time

__version__ = "0.1"

def nonblocking(func):
    """
    Decorator that runs the decorated func in a separate thread
    when called.
    """
    @functools.wraps(func)
    def wrapper(*args):
        thread.start_new_thread(func, args)
    return wrapper

class StoppableThread(threading.Thread):
    """
    Thread class that runs a main() method until the stop() method
    is called.
    """

    def stop(self):
        """
        Stops the main event loop.
        """
        self.running = False

    def main(self):
        """
        Main method to be overridden by subclass that runs each
        event loop iteration.
        """
        pass

    def end(self):
        """
        Called once the thread had been stopped and the final
        iteration of main() has run.
        """
        pass

    def run(self):
        """
        Run main method until stop() is called.
        """
        self.running = True
        while self.running:
            self.main()
            time.sleep(.1)
        self.end()

class Server(StoppableThread):
    """
    Chat server.
    """

    def __init__(self, host, port, shutdown_delay=5):
        """
        Set up the server socket.
        """
        super(Server, self).__init__()
        self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        self.socket.setblocking(False)
        self.socket.bind((host, port))
        self.socket.listen(1)
        self.shutdown_delay = shutdown_delay
        self.users = {}
        self.commands = {
            "!quit": "quit",
            "!users": "list_users",
            "!commands": "list_commands",
        }

    def main(self):
        """
        Main event loop iteration.
        """
        # Accept new connections.
        while True:
            try:
                conn, addr = self.socket.accept()
            except socket.error:
                break
            self.accept(conn)
        # Read from connections.
        for name, conn in self.users.items():
            try:
                message = conn.recv(1024)
            except socket.error:
                continue
            if not message:
                # Empty string is given on disconnect,
                # close connection.
                conn.close()
            else:
                # Handle command if given, otherwise
                # broadcast message.
                message = message.strip()
                try:
                    command = self.commands[message]
                except KeyError:
                    self.broadcast(name, message)
                else:
                    getattr(self, command)(conn)
            # Check for disconnected users and remove them.
            try:
                conn.send("")
            except socket.error:
                del self.users[name]
                self.broadcast(name, action="leaves")

    def end(self):
        """
        Send a shutdown message to all users and close their
        connections.
        """
        message = "shutting down in %s seconds" % self.shutdown_delay
        self.broadcast(action=message)
        time.sleep(self.shutdown_delay)
        for conn in self.users.values():
            conn.close()

    @nonblocking
    def accept(self, conn):
        """
        Call the inner func in a thread so as not to block. Wait for a
        name to be entered from the given connection. Once a name is
        entered, set the connection to non-blocking and add the user to
        the users dict.
        """
        while True:
            conn.send("Please enter your name: ")
            try:
                name = conn.recv(1024).strip()
            except socket.error:
                continue
            if name in self.users.keys():
                conn.send("Name entered is already in use.\n")
            elif name:
                conn.setblocking(False)
                self.users[name] = conn
                conn.send("Welcome %s!\n" % name)
                self.list_commands(conn)
                self.list_users(conn)
                self.broadcast(name, action="joins")
                break

    def broadcast(self, name="", message=None, action=None):
        """
        Send a message to all users from the given name. If no name specified,
        the message is from the server. If no message is specified and an action
        is given, use the action as the message without a colon prefix to
        signify it isn't a message.
        """
        timestamp = time.strftime("[%I:%M:%S]")
        if message is None:
            message = "%s %s %s" % (timestamp, name, action)
        else:
            message = "%s %s: %s" % (timestamp, name, message)
        for to_name, conn in self.users.items():
            if to_name != name:
                try:
                    conn.send(message + "\n")
                except socket.error:
                    pass

    def quit(self, conn):
        """
        Disconnect a connection.
        """
        conn.close()

    def list_users(self, conn):
        """
        Send the list of users to a connection.
        """
        users = sorted(self.users.keys())
        conn.send("Current users are: %s\n" % ", ".join(users))

    def list_commands(self, conn):
        """
        Send the list of commands to a connection.
        """
        commands = sorted(self.commands.keys())
        conn.send("Available commands are: %s\n" % " ".join(commands))

class Client(StoppableThread):
    """
    Chat client.
    """

    def __init__(self, host, port, name, connect_retries=10):
        """
        Set up the client socket and connect to the server..
        """
        super(Client, self).__init__()
        self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.socket.setblocking(False)
        self.name = name
        self.name_sent = False
        while True:
            try:
                self.socket.connect((host, port))
                break
            except socket.error:
                connect_retries -= 1
                if connect_retries > 0:
                    time.sleep(1)
                else:
                    print "Couldn't connect to %s:%s" % (host, port)
                    return

    def main(self):
        """
        Main event loop iteration - read responses from the server.
        On first response, send the specified username.
        """
        try:
            message = self.socket.recv(1024)
        except socket.error:
            time.sleep(.1)
        else:
            if not message:
                self.stop()
            else:
                message = message.strip()
                if not self.name_sent:
                    # Set the username on first response.
                    self.name_sent = True
                    self.socket.send(self.name)
                    self.handle_input()
                else:
                    print message
        # Handle disconnection.
        try:
            self.socket.send("")
        except socket.error:
            self.stop()

    def end(self):
        """
        Close socket on end.
        """
        self.socket.close()

    @nonblocking
    def handle_input(self):
        """
        Reads input from the terminal and sends it as a message.
        """
        while True:
            try:
                self.socket.send(raw_input())
            except socket.error:
                # Connection closed.
                break

def main():
    """
    Start client and/or server based on command line options
    and run them until exit.
    """

    # Get command line options.
    parser = optparse.OptionParser(usage="usage: %prog [options]")
    parser.add_option("-b", "--bind", dest="bind", help="Address for the "
                      "chat server to, in the format host:port")
    parser.add_option("-c", "--client-only", dest="client_only",
                      action="store_true", default=False,
                      help="Only run the client")
    parser.add_option("-s", "--server-only", dest="server_only",
                      action="store_true", default=False,
                      help="Only run the server")
    options, args = parser.parse_args()
    try:
        host, port = options.bind.split(":")
        port = int(port)
    except AttributeError:
        parser.error("Address not specified")
    except ValueError:
        parser.error("Address not in the format host:port")
    if options.client_only and options.server_only:
        parser.error("Cannot specify client-only and server-only")

    # Run server and client.
    if not options.client_only:
        server = Server(host, port)
        server.start()
        print "Listening on %s:%s" % server.socket.getsockname()
        if not options.server_only:
            time.sleep(1)
    if not options.server_only:
        name = raw_input("Please enter your name: ")
        client = Client(host, port, name)
        client.start()

    # Wait for exit.
    while True:
        try:
            time.sleep(.1)
        except (SystemExit, KeyboardInterrupt):
            break
    if not options.server_only:
        client.stop()
    if not options.client_only:
        server.stop()

if __name__ == "__main__":
    main()
<commit_msg>Updated help for command line options.<commit_after>#!/usr/bin/env python

import functools
import optparse
import socket
import thread
import threading
import time

__version__ = "0.1"

def nonblocking(func):
    """
    Decorator that runs the decorated func in a separate thread
    when called.
    """
    @functools.wraps(func)
    def wrapper(*args):
        thread.start_new_thread(func, args)
    return wrapper

class StoppableThread(threading.Thread):
    """
    Thread class that runs a main() method until the stop() method
    is called.
    """

    def stop(self):
        """
        Stops the main event loop.
        """
        self.running = False

    def main(self):
        """
        Main method to be overridden by subclass that runs each
        event loop iteration.
        """
        pass

    def end(self):
        """
        Called once the thread had been stopped and the final
        iteration of main() has run.
        """
        pass

    def run(self):
        """
        Run main method until stop() is called.
        """
        self.running = True
        while self.running:
            self.main()
            time.sleep(.1)
        self.end()

class Server(StoppableThread):
    """
    Chat server.
    """

    def __init__(self, host, port, shutdown_delay=5):
        """
        Set up the server socket.
        """
        super(Server, self).__init__()
        self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        self.socket.setblocking(False)
        self.socket.bind((host, port))
        self.socket.listen(1)
        self.shutdown_delay = shutdown_delay
        self.users = {}
        self.commands = {
            "!quit": "quit",
            "!users": "list_users",
            "!commands": "list_commands",
        }

    def main(self):
        """
        Main event loop iteration.
        """
        # Accept new connections.
        while True:
            try:
                conn, addr = self.socket.accept()
            except socket.error:
                break
            self.accept(conn)
        # Read from connections.
        for name, conn in self.users.items():
            try:
                message = conn.recv(1024)
            except socket.error:
                continue
            if not message:
                # Empty string is given on disconnect,
                # close connection.
                conn.close()
            else:
                # Handle command if given, otherwise
                # broadcast message.
                message = message.strip()
                try:
                    command = self.commands[message]
                except KeyError:
                    self.broadcast(name, message)
                else:
                    getattr(self, command)(conn)
            # Check for disconnected users and remove them.
            try:
                conn.send("")
            except socket.error:
                del self.users[name]
                self.broadcast(name, action="leaves")

    def end(self):
        """
        Send a shutdown message to all users and close their
        connections.
        """
        message = "shutting down in %s seconds" % self.shutdown_delay
        self.broadcast(action=message)
        time.sleep(self.shutdown_delay)
        for conn in self.users.values():
            conn.close()

    @nonblocking
    def accept(self, conn):
        """
        Call the inner func in a thread so as not to block. Wait for a
        name to be entered from the given connection. Once a name is
        entered, set the connection to non-blocking and add the user to
        the users dict.
        """
        while True:
            conn.send("Please enter your name: ")
            try:
                name = conn.recv(1024).strip()
            except socket.error:
                continue
            if name in self.users.keys():
                conn.send("Name entered is already in use.\n")
            elif name:
                conn.setblocking(False)
                self.users[name] = conn
                conn.send("Welcome %s!\n" % name)
                self.list_commands(conn)
                self.list_users(conn)
                self.broadcast(name, action="joins")
                break

    def broadcast(self, name="", message=None, action=None):
        """
        Send a message to all users from the given name. If no name specified,
        the message is from the server. If no message is specified and an action
        is given, use the action as the message without a colon prefix to
        signify it isn't a message.
        """
        timestamp = time.strftime("[%I:%M:%S]")
        if message is None:
            message = "%s %s %s" % (timestamp, name, action)
        else:
            message = "%s %s: %s" % (timestamp, name, message)
        for to_name, conn in self.users.items():
            if to_name != name:
                try:
                    conn.send(message + "\n")
                except socket.error:
                    pass

    def quit(self, conn):
        """
        Disconnect a connection.
        """
        conn.close()

    def list_users(self, conn):
        """
        Send the list of users to a connection.
        """
        users = sorted(self.users.keys())
        conn.send("Current users are: %s\n" % ", ".join(users))

    def list_commands(self, conn):
        """
        Send the list of commands to a connection.
        """
        commands = sorted(self.commands.keys())
        conn.send("Available commands are: %s\n" % " ".join(commands))

class Client(StoppableThread):
    """
    Chat client.
    """

    def __init__(self, host, port, name, connect_retries=10):
        """
        Set up the client socket and connect to the server..
        """
        super(Client, self).__init__()
        self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.socket.setblocking(False)
        self.name = name
        self.name_sent = False
        while True:
            try:
                self.socket.connect((host, port))
                break
            except socket.error:
                connect_retries -= 1
                if connect_retries > 0:
                    time.sleep(1)
                else:
                    print "Couldn't connect to %s:%s" % (host, port)
                    return

    def main(self):
        """
        Main event loop iteration - read responses from the server.
        On first response, send the specified username.
        """
        try:
            message = self.socket.recv(1024)
        except socket.error:
            time.sleep(.1)
        else:
            if not message:
                self.stop()
            else:
                message = message.strip()
                if not self.name_sent:
                    # Set the username on first response.
                    self.name_sent = True
                    self.socket.send(self.name)
                    self.handle_input()
                else:
                    print message
        # Handle disconnection.
        try:
            self.socket.send("")
        except socket.error:
            self.stop()

    def end(self):
        """
        Close socket on end.
        """
        self.socket.close()

    @nonblocking
    def handle_input(self):
        """
        Reads input from the terminal and sends it as a message.
        """
        while True:
            try:
                self.socket.send(raw_input())
            except socket.error:
                # Connection closed.
                break

def main():
    """
    Start client and/or server based on command line options
    and run them until exit.
    """

    # Get command line options.
    parser = optparse.OptionParser(usage="usage: %prog -b host:port [options]")
    parser.add_option("-b", "--bind", dest="bind", help="Address for the "
                      "Grillo server and/or client to use, in the format "
                      "host:port")
    parser.add_option("-c", "--client-only", dest="client_only",
                      action="store_true", default=False,
                      help="Only run the client")
    parser.add_option("-s", "--server-only", dest="server_only",
                      action="store_true", default=False,
                      help="Only run the server")
    options, args = parser.parse_args()
    try:
        host, port = options.bind.split(":")
        port = int(port)
    except AttributeError:
        parser.error("Address not specified")
    except ValueError:
        parser.error("Address not in the format host:port")
    if options.client_only and options.server_only:
        parser.error("Cannot specify client-only and server-only")

    # Run server and client.
    if not options.client_only:
        server = Server(host, port)
        server.start()
        print "Listening on %s:%s" % server.socket.getsockname()
        if not options.server_only:
            time.sleep(1)
    if not options.server_only:
        name = raw_input("Please enter your name: ")
        client = Client(host, port, name)
        client.start()

    # Wait for exit.
    while True:
        try:
            time.sleep(.1)
        except (SystemExit, KeyboardInterrupt):
            break
    if not options.server_only:
        client.stop()
    if not options.client_only:
        server.stop()

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


<commit_before>import os
import subprocess
import re

import sublime

try:
    from . import git_helper
    from .view_collection import ViewCollection
except (ImportError, ValueError):
    import git_helper
    from view_collection import ViewCollection

class GitGutterHandler:

    def __init__(self, view):
        self.load_settings()
        self.view = view
        self.git_temp_file = ViewCollection.git_tmp_file(self.view)
        self.buf_temp_file = ViewCollection.buf_tmp_file(self.view)
        if self.on_disk():
            self.git_tree = git_helper.git_tree(self.view)
            self.git_dir = git_helper.git_dir(self.git_tree)
            self.git_path = git_helper.git_file_path(self.view, self.git_tree)

    def _get_view_encoding(self):
        # get encoding and clean it for python ex: "Western (ISO 8859-1)"
        # NOTE(maelnor): are we need regex here?
        pattern = re.compile(r'.+\((.*)\)')
        encoding = self.view.encoding()
        if encoding == "Undefined":
            encoding = self.view.settings().get('default_encoding')
        if pattern.match(encoding):
            encoding = pattern.sub(r'\1', encoding)

        encoding = encoding.replace('with BOM', '')
        encoding = encoding.replace('Windows', 'cp')
        encoding = encoding.replace('-', '_')
        encoding = encoding.replace(' ', '')

        # work around with ConvertToUTF8 plugin
        origin_encoding = self.view.settings().get('origin_encoding')
        return origin_encoding or encoding

    def on_disk(self):
        # if the view is saved to disk
        return self.view.file_name() is not None

    def reset(self):
        if self.on_disk() and self.git_path and self.view.window():
            self.view.window().run_command('git_gutter')

    def get_git_path(self):
        return self.git_path

    def update_buf_file(self):
        chars = self.view.size()
        region = sublime.Region(0, chars)

        # Try conversion
        try:
            contents = self.view.substr(
                region).encode(self._get_view_encoding())
        except UnicodeError:
            # Fallback to utf8-encoding
            contents = self.view.substr(region).encode('utf-8')
        except LookupError:
            # May encounter an encoding we don't have a codec for
            contents = self.view.substr(region).encode('utf-8')

        contents = contents.replace(b'\r\n', b'\n')
        contents = contents.replace(b'\r', b'\n')
        f = open(self.buf_temp_file.name, 'wb')

        f.write(contents)
        f.close()

    def update_git_file(self):
        # the git repo won't change that often
        # so we can easily wait 5 seconds
        # between updates for performance
        if ViewCollection.git_time(self.view) > 5:
            open(self.git_temp_file.name, 'w').close()
            args = [
                self.git_binary_path,
                '--git-dir=' + self.git_dir,
                '--work-tree=' + self.git_tree,
                'show',
                ViewCollection.get_compare(self.view) + ':' + self.git_path,
            ]
            try:
                contents = self.run_command(args)
                contents = contents.replace(b'\r\n', b'\n')
                contents = contents.replace(b'\r', b'\n')
                f = open(self.git_temp_file.name, 'wb')
                f.write(contents)
                f.close()
                ViewCollection.update_git_time(self.view)
            except Exception:
                pass

    def total_lines(self):
        chars = self.view.size()
        region = sublime.Region(0, chars)
        lines = self.view.lines(region)
        return len(lines)

    # Parse unified diff with 0 lines of context.
    # Hunk range info format:
    #   @@ -3,2 +4,0 @@
    #     Hunk originally starting at line 3, and occupying 2 lines, now
    #     starts at line 4, and occupies 0 lines, i.e. it was deleted.
    #   @@ -9 +10,2 @@
    #     Hunk size can be omitted, and defaults to one line.
    # Dealing with ambiguous hunks:
    #   "A\nB\n" -> "C\n"
    #   Was 'A' modified, and 'B' deleted? Or 'B' modified, 'A' deleted?
    #   Or both deleted? To minimize confusion, let's simply mark the
    #   hunk as modified.
    def process_diff(self, diff_str):
        inserted = []
        modified = []
        deleted = []
        hunk_re = '^@@ \-(\d+),?(\d*) \+(\d+),?(\d*) @@'
        hunks = re.finditer(hunk_re, diff_str, re.MULTILINE)
        for hunk in hunks:
            start = int(hunk.group(3))
            old_size = int(hunk.group(2) or 1)
            new_size = int(hunk.group(4) or 1)
            if not old_size:
                inserted += range(start, start + new_size)
            elif not new_size:
                deleted += [start + 1]
            else:
                modified += range(start, start + new_size)
        if len(inserted) == self.total_lines() and not self.show_untracked:
            # All lines are "inserted"
            # this means this file is either:
            # - New and not being tracked *yet*
            # - Or it is a *gitignored* file
            return ([], [], [])
        else:
            return (inserted, modified, deleted)

    def diff(self):
        if self.on_disk() and self.git_path:
            self.update_git_file()
            self.update_buf_file()
            args = [
                self.git_binary_path, 'diff', '-U0', '--no-color',
                self.ignore_whitespace,
                self.patience_switch,
                self.git_temp_file.name,
                self.buf_temp_file.name,
            ]
            args = list(filter(None, args))  # Remove empty args
            results = self.run_command(args)
            encoding = self._get_view_encoding()
            try:
                decoded_results = results.decode(encoding.replace(' ', ''))
            except UnicodeError:
                decoded_results = results.decode("utf-8")
            return self.process_diff(decoded_results)
        else:
            return ([], [], [])

    def untracked(self):
        return self.handle_files([])

    def ignored(self):
        return self.handle_files(['-i'])

    def handle_files(self, additionnal_args):
        if self.show_untracked and self.on_disk() and self.git_path:
            args = [
                self.git_binary_path,
                '--git-dir=' + self.git_dir,
                '--work-tree=' + self.git_tree,
                'ls-files', '--other', '--exclude-standard',
            ] + additionnal_args + [
                os.path.join(self.git_tree, self.git_path),
            ]
            args = list(filter(None, args))  # Remove empty args
            results = self.run_command(args)
            encoding = self._get_view_encoding()
            try:
                decoded_results = results.decode(encoding.replace(' ', ''))
            except UnicodeError:
                decoded_results = results.decode("utf-8")
            return (decoded_results != "")
        else:
            return False

    def git_commits(self):
        args = [
            self.git_binary_path,
            '--git-dir=' + self.git_dir,
            '--work-tree=' + self.git_tree,
            'log', '--all',
            '--pretty=%s\a%h %an <%aE>\a%ad (%ar)',
            '--date=local', '--max-count=9000'
        ]
        results = self.run_command(args)
        return results

    def git_branches(self):
        args = [
            self.git_binary_path,
            '--git-dir=' + self.git_dir,
            '--work-tree=' + self.git_tree,
            'for-each-ref',
            '--sort=-committerdate',
            '--format=%(subject)\a%(refname)\a%(objectname)',
            'refs/heads/'
        ]
        results = self.run_command(args)
        return results

    def git_tags(self):
        args = [
            self.git_binary_path,
            '--git-dir=' + self.git_dir,
            '--work-tree=' + self.git_tree,
            'show-ref',
            '--tags',
            '--abbrev=7'
        ]
        results = self.run_command(args)
        return results

    def git_current_branch(self):
        args = [
            self.git_binary_path,
            '--git-dir=' + self.git_dir,
            '--work-tree=' + self.git_tree,
            'rev-parse',
            '--abbrev-ref',
            'HEAD'
        ]
        result = self.run_command(args)
        return result

    def run_command(self, args):
        startupinfo = None
        if os.name == 'nt':
            startupinfo = subprocess.STARTUPINFO()
            startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
        proc = subprocess.Popen(args, stdout=subprocess.PIPE,
                                startupinfo=startupinfo, stderr=subprocess.PIPE)
        return proc.stdout.read()

    def load_settings(self):
        self.settings = sublime.load_settings('GitGutter.sublime-settings')
        self.user_settings = sublime.load_settings(
            'Preferences.sublime-settings')

        # Git Binary Setting
        self.git_binary_path = 'git'
        git_binary = self.user_settings.get(
            'git_binary') or self.settings.get('git_binary')
        if git_binary:
            self.git_binary_path = git_binary

        # Ignore White Space Setting
        self.ignore_whitespace = self.settings.get('ignore_whitespace')
        if self.ignore_whitespace == 'all':
            self.ignore_whitespace = '-w'
        elif self.ignore_whitespace == 'eol':
            self.ignore_whitespace = '--ignore-space-at-eol'
        else:
            self.ignore_whitespace = ''

        # Patience Setting
        self.patience_switch = ''
        patience = self.settings.get('patience')
        if patience:
            self.patience_switch = '--patience'

        # Untracked files
        self.show_untracked = self.settings.get(
            'show_markers_on_untracked_file')

        # Show information in status bar
        self.show_status = self.user_settings.get('show_status') or self.settings.get('show_status')
        if self.show_status != 'all' and self.show_status != 'none':
            self.show_status = 'default'
<commit_msg>Fix for invalid UTF-8 and Hexadecimal view<commit_after>import os
import subprocess
import re
import codecs

import sublime

try:
    from . import git_helper
    from .view_collection import ViewCollection
except (ImportError, ValueError):
    import git_helper
    from view_collection import ViewCollection

class GitGutterHandler:

    def __init__(self, view):
        self.load_settings()
        self.view = view
        self.git_temp_file = ViewCollection.git_tmp_file(self.view)
        self.buf_temp_file = ViewCollection.buf_tmp_file(self.view)
        if self.on_disk():
            self.git_tree = git_helper.git_tree(self.view)
            self.git_dir = git_helper.git_dir(self.git_tree)
            self.git_path = git_helper.git_file_path(self.view, self.git_tree)

    def _get_view_encoding(self):
        # get encoding and clean it for python ex: "Western (ISO 8859-1)"
        # NOTE(maelnor): are we need regex here?
        pattern = re.compile(r'.+\((.*)\)')
        encoding = self.view.encoding()
        if encoding == "Undefined":
            encoding = self.view.settings().get('default_encoding')
        if pattern.match(encoding):
            encoding = pattern.sub(r'\1', encoding)

        encoding = encoding.replace('with BOM', '')
        encoding = encoding.replace('Windows', 'cp')
        encoding = encoding.replace('-', '_')
        encoding = encoding.replace(' ', '')

        # work around with ConvertToUTF8 plugin
        origin_encoding = self.view.settings().get('origin_encoding')
        return origin_encoding or encoding

    def on_disk(self):
        # if the view is saved to disk
        return self.view.file_name() is not None

    def reset(self):
        if self.on_disk() and self.git_path and self.view.window():
            self.view.window().run_command('git_gutter')

    def get_git_path(self):
        return self.git_path

    def update_buf_file(self):
        chars = self.view.size()
        region = sublime.Region(0, chars)

        # Try conversion
        try:
            contents = self.view.substr(
                region).encode(self._get_view_encoding())
        except UnicodeError:
            # Fallback to utf8-encoding
            contents = self.view.substr(region).encode('utf-8')
        except LookupError:
            # May encounter an encoding we don't have a codec for
            contents = self.view.substr(region).encode('utf-8')

        contents = contents.replace(b'\r\n', b'\n')
        contents = contents.replace(b'\r', b'\n')
        f = open(self.buf_temp_file.name, 'wb')

        f.write(contents)
        f.close()

    def update_git_file(self):
        # the git repo won't change that often
        # so we can easily wait 5 seconds
        # between updates for performance
        if ViewCollection.git_time(self.view) > 5:
            open(self.git_temp_file.name, 'w').close()
            args = [
                self.git_binary_path,
                '--git-dir=' + self.git_dir,
                '--work-tree=' + self.git_tree,
                'show',
                ViewCollection.get_compare(self.view) + ':' + self.git_path,
            ]
            try:
                contents = self.run_command(args)
                contents = contents.replace(b'\r\n', b'\n')
                contents = contents.replace(b'\r', b'\n')
                f = open(self.git_temp_file.name, 'wb')
                f.write(contents)
                f.close()
                ViewCollection.update_git_time(self.view)
            except Exception:
                pass

    def total_lines(self):
        chars = self.view.size()
        region = sublime.Region(0, chars)
        lines = self.view.lines(region)
        return len(lines)

    # Parse unified diff with 0 lines of context.
    # Hunk range info format:
    #   @@ -3,2 +4,0 @@
    #     Hunk originally starting at line 3, and occupying 2 lines, now
    #     starts at line 4, and occupies 0 lines, i.e. it was deleted.
    #   @@ -9 +10,2 @@
    #     Hunk size can be omitted, and defaults to one line.
    # Dealing with ambiguous hunks:
    #   "A\nB\n" -> "C\n"
    #   Was 'A' modified, and 'B' deleted? Or 'B' modified, 'A' deleted?
    #   Or both deleted? To minimize confusion, let's simply mark the
    #   hunk as modified.
    def process_diff(self, diff_str):
        inserted = []
        modified = []
        deleted = []
        hunk_re = '^@@ \-(\d+),?(\d*) \+(\d+),?(\d*) @@'
        hunks = re.finditer(hunk_re, diff_str, re.MULTILINE)
        for hunk in hunks:
            start = int(hunk.group(3))
            old_size = int(hunk.group(2) or 1)
            new_size = int(hunk.group(4) or 1)
            if not old_size:
                inserted += range(start, start + new_size)
            elif not new_size:
                deleted += [start + 1]
            else:
                modified += range(start, start + new_size)
        if len(inserted) == self.total_lines() and not self.show_untracked:
            # All lines are "inserted"
            # this means this file is either:
            # - New and not being tracked *yet*
            # - Or it is a *gitignored* file
            return ([], [], [])
        else:
            return (inserted, modified, deleted)

    def diff(self):
        if self.on_disk() and self.git_path:
            self.update_git_file()
            self.update_buf_file()
            args = [
                self.git_binary_path, 'diff', '-U0', '--no-color',
                self.ignore_whitespace,
                self.patience_switch,
                self.git_temp_file.name,
                self.buf_temp_file.name,
            ]
            args = list(filter(None, args))  # Remove empty args
            results = self.run_command(args)
            encoding = self._get_view_encoding()
            try:
                decoded_results = results.decode(encoding.replace(' ', ''))
            except UnicodeError:
                try:
                    decoded_results = results.decode("utf-8")
                except UnicodeDecodeError:
                    decoded_results = ""
            except LookupError:
                try:
                    decoded_results = codecs.decode(results)
                except UnicodeDecodeError:
                    decoded_results = ""
            return self.process_diff(decoded_results)
        else:
            return ([], [], [])

    def untracked(self):
        return self.handle_files([])

    def ignored(self):
        return self.handle_files(['-i'])

    def handle_files(self, additionnal_args):
        if self.show_untracked and self.on_disk() and self.git_path:
            args = [
                self.git_binary_path,
                '--git-dir=' + self.git_dir,
                '--work-tree=' + self.git_tree,
                'ls-files', '--other', '--exclude-standard',
            ] + additionnal_args + [
                os.path.join(self.git_tree, self.git_path),
            ]
            args = list(filter(None, args))  # Remove empty args
            results = self.run_command(args)
            encoding = self._get_view_encoding()
            try:
                decoded_results = results.decode(encoding.replace(' ', ''))
            except UnicodeError:
                decoded_results = results.decode("utf-8")
            return (decoded_results != "")
        else:
            return False

    def git_commits(self):
        args = [
            self.git_binary_path,
            '--git-dir=' + self.git_dir,
            '--work-tree=' + self.git_tree,
            'log', '--all',
            '--pretty=%s\a%h %an <%aE>\a%ad (%ar)',
            '--date=local', '--max-count=9000'
        ]
        results = self.run_command(args)
        return results

    def git_branches(self):
        args = [
            self.git_binary_path,
            '--git-dir=' + self.git_dir,
            '--work-tree=' + self.git_tree,
            'for-each-ref',
            '--sort=-committerdate',
            '--format=%(subject)\a%(refname)\a%(objectname)',
            'refs/heads/'
        ]
        results = self.run_command(args)
        return results

    def git_tags(self):
        args = [
            self.git_binary_path,
            '--git-dir=' + self.git_dir,
            '--work-tree=' + self.git_tree,
            'show-ref',
            '--tags',
            '--abbrev=7'
        ]
        results = self.run_command(args)
        return results

    def git_current_branch(self):
        args = [
            self.git_binary_path,
            '--git-dir=' + self.git_dir,
            '--work-tree=' + self.git_tree,
            'rev-parse',
            '--abbrev-ref',
            'HEAD'
        ]
        result = self.run_command(args)
        return result

    def run_command(self, args):
        startupinfo = None
        if os.name == 'nt':
            startupinfo = subprocess.STARTUPINFO()
            startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
        proc = subprocess.Popen(args, stdout=subprocess.PIPE,
                                startupinfo=startupinfo, stderr=subprocess.PIPE)
        return proc.stdout.read()

    def load_settings(self):
        self.settings = sublime.load_settings('GitGutter.sublime-settings')
        self.user_settings = sublime.load_settings(
            'Preferences.sublime-settings')

        # Git Binary Setting
        self.git_binary_path = 'git'
        git_binary = self.user_settings.get(
            'git_binary') or self.settings.get('git_binary')
        if git_binary:
            self.git_binary_path = git_binary

        # Ignore White Space Setting
        self.ignore_whitespace = self.settings.get('ignore_whitespace')
        if self.ignore_whitespace == 'all':
            self.ignore_whitespace = '-w'
        elif self.ignore_whitespace == 'eol':
            self.ignore_whitespace = '--ignore-space-at-eol'
        else:
            self.ignore_whitespace = ''

        # Patience Setting
        self.patience_switch = ''
        patience = self.settings.get('patience')
        if patience:
            self.patience_switch = '--patience'

        # Untracked files
        self.show_untracked = self.settings.get(
            'show_markers_on_untracked_file')

        # Show information in status bar
        self.show_status = self.user_settings.get('show_status') or self.settings.get('show_status')
        if self.show_status != 'all' and self.show_status != 'none':
            self.show_status = 'default'
<|endoftext|>


<commit_before>import webapp2

class MainPage(webapp2.RequestHandler):
    def get(self):
        self.response.headers['Content-Type'] = 'text/plain'
        self.response.write('Hello, World!')

app = webapp2.WSGIApplication([
    ('/', MainPage),
], debug=True)
<commit_msg>sync part2-usingusers branch with documentation https://developers.google.com/appengine/docs/python…<commit_after>from google.appengine.api import users

import webapp2

class MainPage(webapp2.RequestHandler):

    def get(self):

        user = users.get_current_user()

        if user:
            self.response.headers['Content-Type'] = 'text/plain'
            self.response.write('Hello, ' + user.nickname())

        else:
            self.redirect(users.create_login_url(self.request.uri))

app = webapp2.WSGIApplication([
    ('/', MainPage),
], debug=True)
<|endoftext|>


<commit_before>import logging
import collections
import sys
import textract
import json
import glob
import nltk.corpus

# http://mypy.pythonblogs.com/12_mypy/archive/1253_workaround_for_python_bug_ascii_codec_cant_encode_character_uxa0_in_position_111_ordinal_not_in_range128.html
reload(sys)
sys.setdefaultencoding("utf8")

logging.basicConfig(format='%(asctime)s : %(levelname)s :: %(message)s', level=logging.DEBUG)
stop_words = set(nltk.corpus.stopwords.words('english'))
stop_words.update(['new', 'one', 'may', 'made', 'however', 'would', 'toward', '--', 'two', 'even', 'november',
                   'december', 'march', 'much', 'many', 'september', 'october', 'among', 'august', 'make', 'although',
                   'view', 'june', 'might', 'went', 'could', 'must', 'way', 'began', 'us', 'also', 'might', 'become',
                   'seems', 'known', 'months', 'end', 'upon', 'need', 'good', 'seemed', 'begin', 'less', 'more',
                   'thus', 'case', 'mean', 'means', 'main', 'february', 'work', 'play', 'form', 'day', 'first',
                   'second', 'hand', 'come', 'become', 'came', 'became', 'views'])

input_file = None
input_folder = None
with open('frequencies-settings.json') as data_file:
    data = json.load(data_file)
    logging.debug(data)
    if 'input_file' in data.keys():
        input_file = data['input_file']
    elif 'input_folder' in data.keys():
        input_folder = data['input_folder']

most_count = 100
limit = sys.maxint
# limit = 1

words = []
if input_file is not None:
    text = textract.process(input_file)
    current_words = [word.rstrip('?:!.,;') for word in text.lower().split()]
    current_words = [word for word in current_words if len(word) > 1 and word not in stop_words]
    words.extend(current_words)

file_count = 0
if input_folder is not None:
    if not input_folder.endswith('/'):
        input_folder += '/'
    pathname = input_folder + '*.pdf'
    for this_file in glob.glob(pathname=pathname):
        if file_count < limit:
            logging.debug('%d : %s'  % (file_count, this_file))
            text = textract.process(this_file)
            current_words = [word for word in text.lower().split()]
            current_words = [word.rstrip('?:!.,;') for word in current_words]
            current_words = [word for word in current_words if len(word) > 1 and word not in stop_words]
            words.extend(current_words)
            file_count += 1

logging.debug('%d total words/tokens' % len(words))

counts = collections.Counter(words)
most = counts.most_common(most_count)
logging.debug(counts)
for index, item in enumerate(most):
    logging.debug('%s: %s :: %d' % (index + 1, item[0], item[1]))
logging.debug('%d unique words/tokens' % len(counts))
<commit_msg>feature: more stopwords.<commit_after>import logging
import collections
import sys
import textract
import json
import glob
import nltk.corpus

# http://mypy.pythonblogs.com/12_mypy/archive/1253_workaround_for_python_bug_ascii_codec_cant_encode_character_uxa0_in_position_111_ordinal_not_in_range128.html
reload(sys)
sys.setdefaultencoding("utf8")

logging.basicConfig(format='%(asctime)s : %(levelname)s :: %(message)s', level=logging.DEBUG)
stop_words = set(nltk.corpus.stopwords.words('english'))
stop_words.update(['new', 'one', 'may', 'made', 'however', 'would', 'toward', '--', 'two', 'even', 'november',
                   'december', 'march', 'much', 'many', 'september', 'october', 'among', 'august', 'make', 'although',
                   'view', 'june', 'might', 'went', 'could', 'must', 'way', 'began', 'us', 'also', 'might', 'become',
                   'seems', 'known', 'months', 'end', 'upon', 'need', 'good', 'seemed', 'begin', 'less', 'more',
                   'thus', 'case', 'mean', 'means', 'main', 'february', 'work', 'play', 'form', 'day', 'first',
                   'second', 'hand', 'come', 'become', 'came', 'became', 'views', 'open', 'close', 'closed'])

input_file = None
input_folder = None
with open('frequencies-settings.json') as data_file:
    data = json.load(data_file)
    logging.debug(data)
    if 'input_file' in data.keys():
        input_file = data['input_file']
    elif 'input_folder' in data.keys():
        input_folder = data['input_folder']

most_count = 100
limit = sys.maxint
# limit = 1

words = []
if input_file is not None:
    text = textract.process(input_file)
    current_words = [word.rstrip('?:!.,;') for word in text.lower().split()]
    current_words = [word for word in current_words if len(word) > 1 and word not in stop_words]
    words.extend(current_words)

file_count = 0
if input_folder is not None:
    if not input_folder.endswith('/'):
        input_folder += '/'
    pathname = input_folder + '*.pdf'
    for this_file in glob.glob(pathname=pathname):
        if file_count < limit:
            logging.debug('%d : %s'  % (file_count, this_file))
            text = textract.process(this_file)
            current_words = [word for word in text.lower().split()]
            current_words = [word.rstrip('?:!.,;') for word in current_words]
            current_words = [word for word in current_words if len(word) > 1 and word not in stop_words]
            words.extend(current_words)
            file_count += 1

logging.debug('%d total words/tokens' % len(words))

counts = collections.Counter(words)
most = counts.most_common(most_count)
logging.debug(counts)
for index, item in enumerate(most):
    logging.debug('%s: %s :: %d' % (index + 1, item[0], item[1]))
logging.debug('%d unique words/tokens' % len(counts))
<|endoftext|>


<commit_before>#pylint: disable=missing-docstring
#* This file is part of the MOOSE framework
#* https://www.mooseframework.org
#*
#* All rights reserved, see COPYRIGHT for full restrictions
#* https://github.com/idaholab/moose/blob/master/COPYRIGHT
#*
#* Licensed under LGPL 2.1, please see LICENSE for details
#* https://www.gnu.org/licenses/lgpl-2.1.html

import os
import glob
import shutil
import subprocess
import numpy as np
import vtk
import mooseutils
from Options import Option, Options
import AxisOptions
import FontOptions
import LegendOptions

def get_active_filenames(basename, pattern=None):
    """
    Return a list of tuples containing 'active' filenames and modified times.

    Inputs:
        basename[str]: The base filename (e.g., file_out.e)
        pattern[str]: (Optional) Additional files to consider via glob pattern (e.g., file_out.e-s*)
    """

    # List of all matching filenames
    filenames = [basename]
    if pattern:
        filenames += glob.glob(pattern)
    filenames.sort()

    # Minimum filename modified time
    modified = os.path.getmtime(filenames[0]) if os.path.exists(filenames[0]) else 0

    # Populate a list of tuples: (filename, modified time)
    output = []
    for filename in filenames:
        current_modified = os.path.getmtime(filename) if os.path.exists(filename) else 0
        if current_modified >= modified:
            output.append((filename, current_modified))

    return output

def copy_adaptive_exodus_test_files(testbase):
    """
    A helper for copying test Exodus files.
    """
    basename = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', 'tests', 'input',
                                            'step10_micro_out.e'))
    pattern = basename + '-s*'

    testfiles = []
    for src in [basename] + glob.glob(pattern):
        _, ext = os.path.splitext(src)
        dst = os.path.join(os.getcwd(), testbase + ext)
        testfiles.append(dst)
        shutil.copy(src, dst)
    return sorted(testfiles)

def get_bounds_min_max(*all_bounds):
    """
    Returns min,max bounds arrays provided a list of bounds sets.
    """
    xmin = [float('inf'), float('inf'), float('inf')]
    xmax = [float('-inf'), float('-inf'), float('-inf')]

    for bounds in all_bounds:
        for i, j in enumerate([0, 2, 4]):
            xmin[i] = min(xmin[i], bounds[j])
        for i, j in enumerate([1, 3, 5]):
            xmax[i] = max(xmax[i], bounds[j])
    return xmin, xmax

def get_bounds(*sources):
    """
    Returns the bounding box for all supplied sources.
    """
    bnds = []
    for src in sources:
        bnds.append(src.getVTKMapper().GetBounds())
    return get_bounds_min_max(*bnds)

def compute_distance(*sources):
    """
    Returns the distance across the bounding box for all supplied sources.
    """
    xmin, xmax = get_bounds(*sources)
    return np.linalg.norm(np.array(xmax) - np.array(xmin))

def get_min_max(*pairs):
    """
    Retuns the min/max from a set of min/max pairs.
    """
    xmin = float('inf')
    xmax = float('-inf')
    for x0, x1 in pairs:
        xmin = min(xmin, x0)
        xmax = max(xmax, x1)
    return xmin, xmax

def print_camera(camera, prefix='camera', precision=4):
    """
    Prints vtkCamera object to screen.
    """
    if not isinstance(camera, vtk.vtkCamera):
        print "You must supply a vtkCarmera object."
        return

    view_up = camera.GetViewUp()
    position = camera.GetPosition()
    focal = camera.GetFocalPoint()

    def dump(precision, vec):
        """
        Helper for dumping settings.
        """
        p = str(precision)
        frmt = ''.join(['{:', p, '.', p, 'f}'])

        d = ''.join(['(', frmt, ', ', frmt, ', ', frmt, ')'])
        return d.format(*vec)

    return [prefix + '.SetViewUp' + dump(precision, view_up), prefix + '.SetPosition' + \
                                         dump(precision, position), prefix + '.SetFocalPoint' + \
                                         dump(precision, focal)]

def animate(pattern, output, delay=20, restart_delay=500, loop=True):
    """
    Runs ImageMagic convert to create an animate gif from a series of images.
    """
    filenames = glob.glob(pattern)
    delay = [delay]*len(filenames)
    delay[-1] = restart_delay
    cmd = ['convert']
    for d, f in zip(delay, filenames):
        cmd += ['-delay', str(d), f]
    if loop:
        cmd += ['-loop', '0']
    cmd += [output]
    subprocess.call(cmd)

def img2mov(pattern, output, ffmpeg='ffmpeg', duration=60, framerate=None, bitrate='10M',
            num_threads=1, quality=1, dry_run=False, output_framerate_increase=0):
    """
    Use ffmpeg to convert a series of images to a movie.

    Args:
        pattern[str]: The glob pattern defining the files to be converted.
        output[str]: The name of the output file, including the extension.
        ffmpeg[str]: The ffmpeg executable.
        duration[int]: The desired duration of the movie (in seconds)
        framerate[int]: Ignores the duration and sets the movie framerate directly.
        bitrate[str]: The ffmeg "-b:v" setting.
        num_threads[int]: The number of threads to utilize in rendering.
        quality[int]: The ffmpeg quality setting (ranges from 1 to 31).
        dry_run[bool]: When True the command is not executed.
        factor[float]: Output framerate adjustment to help guarantee no dropped frames, if you see
                       drooped frames in ffmpeg output, increase this number.
    """

    # Check ffmpeg
    if not os.path.exists(ffmpeg) and not dry_run:
        msg = "The ffmpeg executable was not located: {}"
        raise mooseutils.MooseException(msg.format(ffmpeg))

    # Compute framerate from the duration if framerate is not given
    if not framerate:
        n = len(glob.glob(pattern))
        framerate = n/duration

    # Determine the video codec
    _, ext = os.path.splitext(output)
    if ext == '.mov':
        codec = 'mpeg2video'
    elif ext == '.mp4':
        codec = 'mpeg4'
    else:
        msg = "Unsupported output format {}, please use '.mov'"
        raise mooseutils.MooseException(msg.format(ffmpeg))

    # Build the command
    cmd = [ffmpeg]
    cmd += ['-pattern_type', 'glob']
    cmd += ['-framerate', str(framerate)]
    cmd += ['-i', pattern]
    cmd += ['-c:v', codec]
    cmd += ['-b:v', bitrate]
    cmd += ['-pix_fmt', 'yuv420p']
    cmd += ['-q:v', str(quality)]
    cmd += ['-threads', str(num_threads)]
    cmd += ['-framerate', str(framerate + output_framerate_increase)]
    cmd += [output]

    c = ' '.join(cmd)
    print '{0}\n{1}\n{0}'.format('-'*(len(c)), c)
    if not dry_run:
        subprocess.call(cmd)
<commit_msg>Improve ffmpeg location search for chigger.utils.img2mov<commit_after>#pylint: disable=missing-docstring
#* This file is part of the MOOSE framework
#* https://www.mooseframework.org
#*
#* All rights reserved, see COPYRIGHT for full restrictions
#* https://github.com/idaholab/moose/blob/master/COPYRIGHT
#*
#* Licensed under LGPL 2.1, please see LICENSE for details
#* https://www.gnu.org/licenses/lgpl-2.1.html

import os
import glob
import shutil
import subprocess
import numpy as np
import vtk
import mooseutils
from Options import Option, Options
import AxisOptions
import FontOptions
import LegendOptions

def get_active_filenames(basename, pattern=None):
    """
    Return a list of tuples containing 'active' filenames and modified times.

    Inputs:
        basename[str]: The base filename (e.g., file_out.e)
        pattern[str]: (Optional) Additional files to consider via glob pattern (e.g., file_out.e-s*)
    """

    # List of all matching filenames
    filenames = [basename]
    if pattern:
        filenames += glob.glob(pattern)
    filenames.sort()

    # Minimum filename modified time
    modified = os.path.getmtime(filenames[0]) if os.path.exists(filenames[0]) else 0

    # Populate a list of tuples: (filename, modified time)
    output = []
    for filename in filenames:
        current_modified = os.path.getmtime(filename) if os.path.exists(filename) else 0
        if current_modified >= modified:
            output.append((filename, current_modified))

    return output

def copy_adaptive_exodus_test_files(testbase):
    """
    A helper for copying test Exodus files.
    """
    basename = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', 'tests', 'input',
                                            'step10_micro_out.e'))
    pattern = basename + '-s*'

    testfiles = []
    for src in [basename] + glob.glob(pattern):
        _, ext = os.path.splitext(src)
        dst = os.path.join(os.getcwd(), testbase + ext)
        testfiles.append(dst)
        shutil.copy(src, dst)
    return sorted(testfiles)

def get_bounds_min_max(*all_bounds):
    """
    Returns min,max bounds arrays provided a list of bounds sets.
    """
    xmin = [float('inf'), float('inf'), float('inf')]
    xmax = [float('-inf'), float('-inf'), float('-inf')]

    for bounds in all_bounds:
        for i, j in enumerate([0, 2, 4]):
            xmin[i] = min(xmin[i], bounds[j])
        for i, j in enumerate([1, 3, 5]):
            xmax[i] = max(xmax[i], bounds[j])
    return xmin, xmax

def get_bounds(*sources):
    """
    Returns the bounding box for all supplied sources.
    """
    bnds = []
    for src in sources:
        bnds.append(src.getVTKMapper().GetBounds())
    return get_bounds_min_max(*bnds)

def compute_distance(*sources):
    """
    Returns the distance across the bounding box for all supplied sources.
    """
    xmin, xmax = get_bounds(*sources)
    return np.linalg.norm(np.array(xmax) - np.array(xmin))

def get_min_max(*pairs):
    """
    Retuns the min/max from a set of min/max pairs.
    """
    xmin = float('inf')
    xmax = float('-inf')
    for x0, x1 in pairs:
        xmin = min(xmin, x0)
        xmax = max(xmax, x1)
    return xmin, xmax

def print_camera(camera, prefix='camera', precision=4):
    """
    Prints vtkCamera object to screen.
    """
    if not isinstance(camera, vtk.vtkCamera):
        print "You must supply a vtkCarmera object."
        return

    view_up = camera.GetViewUp()
    position = camera.GetPosition()
    focal = camera.GetFocalPoint()

    def dump(precision, vec):
        """
        Helper for dumping settings.
        """
        p = str(precision)
        frmt = ''.join(['{:', p, '.', p, 'f}'])

        d = ''.join(['(', frmt, ', ', frmt, ', ', frmt, ')'])
        return d.format(*vec)

    return [prefix + '.SetViewUp' + dump(precision, view_up), prefix + '.SetPosition' + \
                                         dump(precision, position), prefix + '.SetFocalPoint' + \
                                         dump(precision, focal)]

def animate(pattern, output, delay=20, restart_delay=500, loop=True):
    """
    Runs ImageMagic convert to create an animate gif from a series of images.
    """
    filenames = glob.glob(pattern)
    delay = [delay]*len(filenames)
    delay[-1] = restart_delay
    cmd = ['convert']
    for d, f in zip(delay, filenames):
        cmd += ['-delay', str(d), f]
    if loop:
        cmd += ['-loop', '0']
    cmd += [output]
    subprocess.call(cmd)

def img2mov(pattern, output, ffmpeg=None, duration=60, framerate=None, bitrate='10M',
            num_threads=1, quality=1, dry_run=False, output_framerate_increase=0):
    """
    Use ffmpeg to convert a series of images to a movie.

    Args:
        pattern[str]: The glob pattern defining the files to be converted.
        output[str]: The name of the output file, including the extension.
        ffmpeg[str]: The ffmpeg executable.
        duration[int]: The desired duration of the movie (in seconds)
        framerate[int]: Ignores the duration and sets the movie framerate directly.
        bitrate[str]: The ffmeg "-b:v" setting.
        num_threads[int]: The number of threads to utilize in rendering.
        quality[int]: The ffmpeg quality setting (ranges from 1 to 31).
        dry_run[bool]: When True the command is not executed.
        factor[float]: Output framerate adjustment to help guarantee no dropped frames, if you see
                       drooped frames in ffmpeg output, increase this number.
    """

    # Locate ffmpeg
    if ffmpeg is None:
        if os.path.exists('/usr/bin/ffmpeg'):
            ffmpeg = '/usr/bin/ffmpeg'
    if ffmpeg is None:
        if os.path.exists(os.path.join(os.getenv('HOME'), 'ffmpeg')):
            ffmpeg = os.path.join(os.getenv('HOME'), 'ffmpeg')

    ffmpeg = os.path.abspath(ffmpeg)
    if not os.path.exists(ffmpeg) and not dry_run:
        msg = "The ffmpeg executable was not located: {}"
        raise mooseutils.MooseException(msg.format(ffmpeg))

    # Compute framerate from the duration if framerate is not given
    if not framerate:
        n = len(glob.glob(pattern))
        framerate = n/duration

    # Determine the video codec
    _, ext = os.path.splitext(output)
    if ext == '.mov':
        codec = 'mpeg2video'
    elif ext == '.mp4':
        codec = 'mpeg4'
    else:
        msg = "Unsupported output format {}, please use '.mov'"
        raise mooseutils.MooseException(msg.format(ffmpeg))

    # Build the command
    cmd = [ffmpeg]
    cmd += ['-pattern_type', 'glob']
    cmd += ['-framerate', str(framerate)]
    cmd += ['-i', pattern]
    cmd += ['-c:v', codec]
    cmd += ['-b:v', bitrate]
    cmd += ['-pix_fmt', 'yuv420p']
    cmd += ['-q:v', str(quality)]
    cmd += ['-threads', str(num_threads)]
    cmd += ['-framerate', str(framerate + output_framerate_increase)]
    cmd += [output]

    c = ' '.join(cmd)
    print '{0}\n{1}\n{0}'.format('-'*(len(c)), c)
    if not dry_run:
        subprocess.call(cmd)
<|endoftext|>