<commit_before># -*- coding: utf-8 -*-
###############################################################################
#
# ODOO (ex OpenERP)
# Open Source Management Solution
# Copyright (C) 2001-2015 Micronaet S.r.l. (<http://www.micronaet.it>)
# Developer: Nicola Riolini @thebrush (<https://it.linkedin.com/in/thebrush>)
# 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 os
import sys
import logging
import netsvc
import csv
import decimal_precision as dp
from os import listdir
from osv import fields, osv, expression, orm
from datetime import datetime, timedelta
from tools.translate import _
from tools import (DEFAULT_SERVER_DATE_FORMAT,
    DEFAULT_SERVER_DATETIME_FORMAT,
    DATETIME_FORMATS_MAP,
    )

_logger = logging.getLogger(__name__)

class account_analytic_expense_km(osv.osv):
    ''' Add schedule method and override split method
    '''
    _name = 'account.analytic.expense.km'
    _description = 'Monthly transport km'
    _rec_name = 'account_id'

    # -------------------------------------------------------------------------
    #                                 Scheduled
    # -------------------------------------------------------------------------
    def schedule_csv_accounting_transport_movement_import(
            self, cr, uid, path='~/etl/transport', separator=';', header=0,
            verbose=100, bof='transport', context=None):
        ''' Import function that read in:
            path: folder where all transport Km file are
            separator: csv file format have this column separator
            header: and total line header passed
            verbose: every x record log event of importation
            bof: the input file must start with this string, after:
                YYMM.csv for get also the ref. month
            context: context for this function
        '''
        from os.path import isfile, join
        account_pool = self.pool.get('account.analytic.account')

        # --------------------------------
        # Utility: function for procedure:
        # --------------------------------
        def format_string(value, default=''):
            try:
                return value.strip() or default
            except:
                return default

        def format_date(value):
            return value

        def format_float(value):
            try:
                value = value.replace(',', '.')
                return float(value)
            except:
                return 0.0

        path = os.path.expanduser(path)
        trans_file = [
            filename for filename in listdir(path) if
                isfile(join(path, filename)) and filename.startswith(bof)
                and len(filename) == (len(bof) + 8)]

        trans_file.sort() # for have last price correct
        _logger.info("Start auto import of file transport")
        import pdb; pdb.set_trace()
        for filename in trans_file:
            try:
                _logger.info("Load and import file %s" % filename)
                error = []
                year_month = os.path.splitext(filename)[0][-4:]

                # --------------------------------
                # Remove all line for that period:
                # --------------------------------
                item_ids = self.search(cr, uid, [
                    ('month', '=', year_month),
                    ], context=context)
                self.unlink(cr, uid, item_ids, context=context)

                # ---------------
                # Load from file:
                # ---------------
                i = -header
                f = open(filename, 'rb')
                for line in f:
                    i += 1
                    if i <= 0: # jump header line
                        continue

                    line = line.strip().split(separator)

                    # Parse file:
                    code = format_string(line[0])
                    km = format_float(line[1])

                    # Check contract:
                    if not code or not km:
                        _logger.warning(_('%s. Code or Km not found') % i)
                        continue

                    account_ids = account_pool.search(cr, uid, [
                        ('code', '=', code)], context=context)

                    if not account_ids:
                        _logger.error(
                            _('%s. Code not found on OpenERP: %s') % (i, code))
                        continue
                    elif len(account_ids) > 1:
                        _logger.error(
                            _('%s. More than one code found (%s): %s') % (
                                i, len(account_ids), code))
                        continue
                    self.create(cr, uid, {
                        'account_id': account_ids[0],
                        'km': km,
                        'month': year_month,
                        }, context=context)
                f.close()

                # History file:
                os.rename(
                    os.path.join(path, filename),
                    os.path.join(path, 'history', '%s.%s' % (
                        datetime.now().strftime('%Y%m%d.%H%M%S'),
                        filename, )),
                    )

            except:
                _logger.error('No correct file format: %s' % filename)
                _logger.error((sys.exc_info(), ))
        _logger.info("End auto import of file transport")
        return True

    _columns = {
         'account_id': fields.many2one('account.analytic.account', 'Account',
             required=True),
         'km': fields.float('Km', digits=(16, 2),
             required=True),
         'month': fields.char('Month', size=4, help='Format YYMM',
             required=True),
         }
account_analytic_expense_km()

class account_analytic_expense(osv.osv):
    ''' Add schedule method and override split method
    '''
    _name = 'account.analytic.expense'
    _inherit = 'account.analytic.expense'

    # Utility:
    def get_transport_splitted_account(self, cr, uid, context=None):
        ''' Function to be written, for now is overrided with module
            contract_manage_transport for temporary phase
            Costs will be calculated depend on Km for every contract
        '''
        # TODO change all:
        data = {}

        intervent_pool = self.pool.get('hr.analytic.timesheet')
        employee_pool = self.pool.get('hr.employee')
        account_pool = self.pool.get('account.analytic.account')

        if not department_id: # TODO all?
            _logger.error(
                _('Cannot split voucher if department is not present!'))

        # ------------------------------
        # List of user that has voucher:
        # ------------------------------
        employee_ids = employee_pool.search(cr, uid, [
            ('has_voucher', '=', True),
            # TODO Note: employee should work for other account, so no filter:
            #('department_id', '=', department_id),
            ], context=context)
        voucher_user_ids = [
            item.user_id.id for item in employee_pool.browse(
                cr, uid, employee_ids, context=context) if item.user_id]
        if not voucher_user_ids:
            _logger.error(
                _('Cannot find active user in dep. selected [%s:%s] (lim. %s)'
                ) % (date_from, date_to, limit, limit))
            return {}

        # ------------------------------
        # Account not cancel and :
        # ------------------------------
        # TODO check date for closing ?
        account_ids = account_pool.search(cr, uid, [
            ('department_id', '=', department_id),
            ('state', '!=', 'cancel'), # Active (or closed) # TODO necessary?
            ('not_working', '=', False), # Working account
            ('is_recover', '=', False), # Not recover account
            ('is_contract', '=', True), # Is contract
            ], context=context)
        if not account_ids:
            _logger.error(
                _('Cannot find active account [%s:%s]') % (
                    date_from, date_to, limit))
            return {}

        # ------------------------------------------------------
        # List of intervent in period for user that has voucher:
        # ------------------------------------------------------
        intervent_ids = intervent_pool.search(cr, uid, [
            ('date', '>=', date_from),
            ('date', '<', date_to),
            ('user_id', 'in', voucher_user_ids),
            ('account_id', 'in', account_ids)
            ])

        # -------------------------------------------------------------
        # Load database for populate limit elements and account + hours
        # -------------------------------------------------------------
        for intervent in intervent_pool.browse(
                cr, uid, intervent_ids, context=context):
            key = (intervent.date, intervent.user_id.id)
            if key not in data:
                data[key] = [0, {}] # day hours, dict of ID int: hour

            data[key][0] += intervent.unit_amount # update duration
            if intervent.account_id in data[key][1]:
                data[key][1][intervent.account_id.id] += intervent.unit_amount
            else:
                data[key][1][intervent.account_id.id] = intervent.unit_amount

        # -------------------------------------
        # Loop for clean database (test limit):
        # -------------------------------------
        res = {}
        total = 0.0
        for item in data:
            if data[item][0] < limit:
                continue # jump, no dinner
            for account_id in data[item][1]:
                if account_id not in res:
                    res[account_id] = 0

                res[account_id] += data[item][1][account_id] # total hours
                total += data[item][1][account_id]

        # -----------------------------------
        # Update with amount splitted (rate):
        # -----------------------------------
        if not total:
            _logger.error(_(
                'Total = 0 cannot split voucher amount: %s!') % amount)
            return {}
        rate = amount / total
        for item in res:
            res[item] *= rate
        # TODO keep line with amount 0?
        return res
        return {}
account_analytic_expense()
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
<commit_msg>Start split<commit_after># -*- coding: utf-8 -*-
###############################################################################
#
# ODOO (ex OpenERP)
# Open Source Management Solution
# Copyright (C) 2001-2015 Micronaet S.r.l. (<http://www.micronaet.it>)
# Developer: Nicola Riolini @thebrush (<https://it.linkedin.com/in/thebrush>)
# 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 os
import sys
import logging
import netsvc
import csv
import decimal_precision as dp
from os import listdir
from osv import fields, osv, expression, orm
from datetime import datetime, timedelta
from tools.translate import _
from tools import (DEFAULT_SERVER_DATE_FORMAT,
    DEFAULT_SERVER_DATETIME_FORMAT,
    DATETIME_FORMATS_MAP,
    )

_logger = logging.getLogger(__name__)

class account_analytic_expense_km(osv.osv):
    ''' Add schedule method and override split method
    '''
    _name = 'account.analytic.expense.km'
    _description = 'Monthly transport km'
    _rec_name = 'account_id'
    _order = 'month'

    # -------------------------------------------------------------------------
    #                                 Scheduled
    # -------------------------------------------------------------------------
    def schedule_csv_accounting_transport_movement_import(
            self, cr, uid, path='~/etl/transport', separator=';', header=0,
            verbose=100, bof='transport', context=None):
        ''' Import function that read in:
            path: folder where all transport Km file are
            separator: csv file format have this column separator
            header: and total line header passed
            verbose: every x record log event of importation
            bof: the input file must start with this string, after:
                YYMM.csv for get also the ref. month
            context: context for this function
        '''
        from os.path import isfile, join
        account_pool = self.pool.get('account.analytic.account')

        # --------------------------------
        # Utility: function for procedure:
        # --------------------------------
        def format_string(value, default=''):
            try:
                return value.strip() or default
            except:
                return default

        def format_date(value):
            return value

        def format_float(value):
            try:
                value = value.replace(',', '.')
                return float(value)
            except:
                return 0.0

        path = os.path.expanduser(path)
        trans_file = [
            filename for filename in listdir(path) if
                isfile(join(path, filename)) and filename.startswith(bof)
                and len(filename) == (len(bof) + 8)]

        trans_file.sort() # for have last price correct
        _logger.info("Start auto import of file transport")

        for filename in trans_file:
            try:
                _logger.info("Load and import file %s" % filename)
                error = []
                year_month = os.path.splitext(filename)[0][-4:]

                # --------------------------------
                # Remove all line for that period:
                # --------------------------------
                item_ids = self.search(cr, uid, [
                    ('month', '=', year_month),
                    ], context=context)
                self.unlink(cr, uid, item_ids, context=context)

                # ---------------
                # Load from file:
                # ---------------
                i = -header
                fullpath = join(path, filename)
                f = open(fullpath, 'rb')
                for line in f:
                    i += 1
                    if i <= 0: # jump header line
                        continue

                    line = line.strip().split(separator)

                    # Parse file:
                    code = format_string(line[0])
                    km = format_float(line[1])

                    # Check contract:
                    if not code or not km:
                        _logger.warning(_('%s. Code or Km not found') % i)
                        continue

                    account_ids = account_pool.search(cr, uid, [
                        ('code', '=', code)], context=context)

                    if not account_ids:
                        _logger.error(
                            _('%s. Code not found on OpenERP: %s') % (i, code))
                        continue
                    elif len(account_ids) > 1:
                        _logger.error(
                            _('%s. More than one code found (%s): %s') % (
                                i, len(account_ids), code))
                        continue
                    self.create(cr, uid, {
                        'account_id': account_ids[0],
                        'km': km,
                        'month': year_month,
                        }, context=context)
                f.close()

                # History file:
                os.rename(
                    os.path.join(path, filename),
                    os.path.join(path, 'history', '%s.%s' % (
                        datetime.now().strftime('%Y%m%d.%H%M%S'),
                        filename, )),
                    )

            except:
                _logger.error('No correct file format: %s' % filename)
                _logger.error((sys.exc_info(), ))
        _logger.info("End auto import of file transport")
        return True

    _columns = {
         'account_id': fields.many2one('account.analytic.account', 'Account',
             required=True),
         'km': fields.float('Km', digits=(16, 2),
             required=True),
         'month': fields.char('Month', size=4, help='Format YYMM',
             required=True),
         }
account_analytic_expense_km()

class account_analytic_expense(osv.osv):
    ''' Add schedule method and override split method
    '''
    _name = 'account.analytic.expense'
    _inherit = 'account.analytic.expense'

    # Utility:
    def get_transport_splitted_account(self, cr, uid, context=None):
        ''' Function to be written, for now is overrided with module
            contract_manage_transport for temporary phase
            Costs will be calculated depend on Km for every contract
        '''
        # TODO change all:
        data = {}

        intervent_pool = self.pool.get('hr.analytic.timesheet')
        employee_pool = self.pool.get('hr.employee')
        account_pool = self.pool.get('account.analytic.account')

        if not department_id: # TODO all?
            _logger.error(
                _('Cannot split voucher if department is not present!'))

        # ------------------------------
        # List of user that has voucher:
        # ------------------------------
        employee_ids = employee_pool.search(cr, uid, [
            ('has_voucher', '=', True),
            # TODO Note: employee should work for other account, so no filter:
            #('department_id', '=', department_id),
            ], context=context)
        voucher_user_ids = [
            item.user_id.id for item in employee_pool.browse(
                cr, uid, employee_ids, context=context) if item.user_id]
        if not voucher_user_ids:
            _logger.error(
                _('Cannot find active user in dep. selected [%s:%s] (lim. %s)'
                ) % (date_from, date_to, limit, limit))
            return {}

        # ------------------------------
        # Account not cancel and :
        # ------------------------------
        # TODO check date for closing ?
        account_ids = account_pool.search(cr, uid, [
            ('department_id', '=', department_id),
            ('state', '!=', 'cancel'), # Active (or closed) # TODO necessary?
            ('not_working', '=', False), # Working account
            ('is_recover', '=', False), # Not recover account
            ('is_contract', '=', True), # Is contract
            ], context=context)
        if not account_ids:
            _logger.error(
                _('Cannot find active account [%s:%s]') % (
                    date_from, date_to, limit))
            return {}

        # ------------------------------------------------------
        # List of intervent in period for user that has voucher:
        # ------------------------------------------------------
        intervent_ids = intervent_pool.search(cr, uid, [
            ('date', '>=', date_from),
            ('date', '<', date_to),
            ('user_id', 'in', voucher_user_ids),
            ('account_id', 'in', account_ids)
            ])

        # -------------------------------------------------------------
        # Load database for populate limit elements and account + hours
        # -------------------------------------------------------------
        for intervent in intervent_pool.browse(
                cr, uid, intervent_ids, context=context):
            key = (intervent.date, intervent.user_id.id)
            if key not in data:
                data[key] = [0, {}] # day hours, dict of ID int: hour

            data[key][0] += intervent.unit_amount # update duration
            if intervent.account_id in data[key][1]:
                data[key][1][intervent.account_id.id] += intervent.unit_amount
            else:
                data[key][1][intervent.account_id.id] = intervent.unit_amount

        # -------------------------------------
        # Loop for clean database (test limit):
        # -------------------------------------
        res = {}
        total = 0.0
        for item in data:
            if data[item][0] < limit:
                continue # jump, no dinner
            for account_id in data[item][1]:
                if account_id not in res:
                    res[account_id] = 0

                res[account_id] += data[item][1][account_id] # total hours
                total += data[item][1][account_id]

        # -----------------------------------
        # Update with amount splitted (rate):
        # -----------------------------------
        if not total:
            _logger.error(_(
                'Total = 0 cannot split voucher amount: %s!') % amount)
            return {}
        rate = amount / total
        for item in res:
            res[item] *= rate
        # TODO keep line with amount 0?
        return res
        return {}
account_analytic_expense()
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
<|endoftext|>


<commit_before>import os, sqlite3, json, random, markovify, re
from colorama import init, Fore, Style
from aiotg import Bot
from furry import Wolfe

with open("rp_data.txt", "r") as f:
    text = f.read()

text_model = markovify.NewlineText(text, state_size=2)
del text

CACHE_DIR = 'cache/'
RES_FOLDER = 'res/'

con = sqlite3.connect('wolfe.db')

wolfe = Wolfe(con)
bot = Bot(os.environ["API_TOKEN"])

basekeyboard = {'keyboard': [[{'text': '💡 Suggest'},{'text': '⭐ Vote'}],[{'text': '⚠ Report'},{'text': '🐾 Credits'}]], 'one_time_keyboard': True, 'resize_keyboard': True}

@bot.command(r"^\/(help|start)(\s*$|@WolfeLegacyBB?ot)") # Don't match commands aimed at other bots
async def welcome(chat, match):
	await chat.send_sticker(sticker="BQADAwADAgADZUASA3hbI2mGeTbkAg")
	await chat.send_text("\
	Hello, welcome to WolfeBot. This bot is not completely stable yet, so don't be alarmed if it stops working for a bit!\n\n\
	For further info please visit the channel @WolfeBotNews\n\
	Bug reports and feature requests ==> https://github.com/TNTINC/WolfeBot/issues \n\
	If it goes absolutely haywire, throw a line at @icefla", parse_mode="HTML")
	return

@bot.command(r'^\/debugdump')
def dump(chat, match):
	return chat.reply(str(chat.message["from"]["id"]) + str(chat.message["chat"]["id"]))

@bot.command(r'^fml')
def weather(chat, match):
	return chat.reply('*fucks your life*')

# Roleplay (owo)
@bot.command(r'\*(.+)\*')
def roleplay(chat, match):
	if 'reply_to_message' in chat.message and chat.message['reply_to_message']['from']['id'] == 194903852:
		return chat.reply("*%s*" % text_model.make_short_sentence(200, tries=200).strip(" .*"))

# Respond to OwO appropriately
@bot.command(r'^OwO')
def owo(chat, match):
	owo = ['whats this??', '*notices ur buldge*', '>//w//<', '*pounces on u*', '*sneaks in your bed and cuddles u*', '*nozzles u*', '*pounces on u and sinks his nozzle inside your fluffy fur*', '*scratches ur ears* x3']
	return chat.send_text(random.choice(owo))

# just why
@bot.command(r'^wolfe sieg')
def owo(chat, match):
	owo = ['What the fuck is wrong with you', 'No.', 'Can we stop please?', 'Is it really necessary?','What about you stop?', 'WHY', 'I wish I didn\'t read tbh.', 'Uh, okay, i guess', 'No, no NO NO NO', 'I\'d rather not reply', 'Hitler was overrated tbh', 'True story bro']
	return chat.send_text(random.choice(owo))

# Stand up for self
@bot.command(r'^wolfe kys')
def owo(chat, match):
	owo = ['No u', 'u', 'no', 'consider suicide', 'How can i kill myself if i\'m a bunch of bits?', 'why would i', 'i see no reason', 'uhm', 'thats okay', 'ehm', 'your fake and gay']
	return chat.send_text(random.choice(owo))

# Query the database for an image and send it
@bot.command(r'\/?yiff\s*$')
async def yiff(chat, match):
	"""
	Send a random approved image from the database.
	"""
	r = con.execute('SELECT path, tg_id, id FROM media WHERE approved = 1 ORDER BY random() LIMIT 1').fetchone()

	keyboard = {'inline_keyboard': [[{'text': '👍', 'callback_data': 'lke_%s' % r[2]},{'text': '👎', 'callback_data': 'dke_%s' % r[2]},{'text': '❤ Fav', 'callback_data': 'fav_%s' % r[2]}]]}

	# No need to reupload if image was already uploaded
	if r[1]:
		try:
			res = await chat.send_photo(photo=r[1]) #, reply_markup=json.dumps(keyboard))
		except RuntimeError:
			print("Failed sending cached image %s" % r[0])
		else:
			return

	with open("%s%s" % (RES_FOLDER, r[0]), 'rb') as f:
		tres = await chat.send_photo(f) #, reply_markup=json.dumps(keyboard))

	if tres['ok']:
		con.execute('UPDATE media SET tg_id = ? WHERE path = ?', (tres['result']['photo'][-1]['file_id'], r[0]))
		con.commit()

# If someone replies "fullsize" to an image we've sent, send the full image uncompressed
@bot.command(r'^(\/?)fullsize')
async def fullsize(chat, match):
	"""
	Send the full version of an image
	"""
	if 'reply_to_message' in chat.message and 'photo' in chat.message['reply_to_message']:
		pid = chat.message['reply_to_message']['photo'][-1]['file_id']

		res = con.execute('SELECT path FROM media WHERE tg_id = ?', (pid,)).fetchone()
		if res:
			with open("%s%s" % (RES_FOLDER, res[0]), 'rb') as f:
				a = await chat.send_document(f, caption='Here you go!')
	return

# Flag an image for moderation
@bot.command(r'^(\/?)delete')
def disapprove(chat, match):
	"""
	Flag an image for moderation.

	Delete the image message, set the approved status of it to 0 in the database and notify @icefla.
	"""
	if 'reply_to_message' in chat.message \
		and 'photo' in chat.message["reply_to_message"]:
		pid = chat.message['reply_to_message']['photo'][-1]['file_id']
		res = con.execute('SELECT path, id FROM media WHERE tg_id = ?', (pid,)).fetchone()
		if res:
			print('[WARN] Soft deleting %s !!!' % res[0])
			chat.reply("Deleting...")

			# Delete the message
			bot.api_call("deleteMessage",
				chat_id = chat.message["chat"]["id"],
				message_id = chat.message["reply_to_message"]["message_id"]
			)

			# Set the photo's approved state to false
			con.execute(
				'UPDATE media SET approved = 0 WHERE tg_id = ?',
				(pid,)
			)
			con.commit()

			# Notify @icefla
			bot.api_call("sendMessage",
				text="Something was flagged! : %s : %s" % (res[1],res[0]),
				chat_id="-262778980"
			)

		else:
			return chat.reply('This image doesn\'t exist!')

@bot.command("/id (.?)$")
def send_image_by_id(chat, match):
	try:
		photo_id = int(match[1])
	except:
		return

	r = con.execute(
		'SELECT tg_id, path FROM media WHERE id = ?',
		(photo_id,)
	).fetchone()

	if r:

		tg_id = r[0]
		path = r[1]

		try:
			print("Sent photo %s from cache" % match[1])
			return chat.send_photo(photo=tg_id)
		except:
			print("Sent photo %s from disk" % match[1])
			return chat.send_photo("%s%s" % (RES_FOLDER,path))
	else:
		return chat.reply("Image not found")

# wolfe yiff me
@bot.command(r'^wolfe (.+) me')
def roleplay(chat, match):
	return chat.send_text('*%ss %s*' % (match.group(1), chat.message['from']['first_name']))

# <3
@bot.command('who\'s keo?')
def keo(chat, match):
	return chat.send_text('A really really cute fox!')

# Praise the bulge
@bot.command('bulge')
def bulge(chat, match):
	if 'reply_to_message' in chat.message and chat.message['reply_to_message']['from']['id'] == 194903852:
		keyboard = {'inline_keyboard': [[{'text': '🍆', 'url': 'https://t.me/bulge'},{'text': '🍆', 'url': 'https://t.me/bulge'},{'text': '🍆', 'url': 'https://t.me/bulge'},{'text': '🍆', 'url': 'https://t.me/bulge'},{'text': '🍆', 'url': 'https://t.me/bulge'}]]}
		return chat.send_text(random.choice(['Did someone say bulge?','*notices your buldge*', 'OwO', 'Murr~', 'Bulge?', 'I happen to have a lot of bulges.']), reply_markup=json.dumps(keyboard))

#@bot.callback
def callback(chat, cq):

	action, num = cq.data.split('_')

	replies = {}
	replies['lke'] = 'You like this'
	replies['dke'] = 'You dislike this'
	replies['fav'] = 'Added into your favourites'

	value = {'lke': 1, 'dke': -1}

	return cq.answer(text=replies[action])

@bot.inline
def inline(request):
	r = con.execute(
		'SELECT tg_id, id FROM media WHERE tg_id IS NOT NULL '
		'ORDER BY random() LIMIT 25'
	).fetchall()
	return request.answer(
		results=
			[{
				'type': 'photo',
				'id': str(pic[1]),
				'photo_file_id': pic[0]
			} for pic in r],
		cache_time=0,
		is_personal=True,
		next_offset='Yolo'
	)

if __name__ == '__main__':
	bot.run()

<commit_msg>Made debugdump return useful information, and Made inline queries display only approved images.<commit_after>import os, sqlite3, json, random, markovify, re, time
from colorama import init, Fore, Style
from aiotg import Bot

START_TIME = time.time()
REQNUM = 0

with open("rp_data.txt", "r") as f:
    text = f.read()

text_model = markovify.NewlineText(text, state_size=2)
del text

vs = "V0.2"

CACHE_DIR = 'cache/'
RES_FOLDER = 'res/'

con = sqlite3.connect('wolfe.db')

bot = Bot(os.environ["API_TOKEN"])

basekeyboard = {'keyboard': [[{'text': '💡 Suggest'},{'text': '⭐ Vote'}],[{'text': '⚠ Report'},{'text': '🐾 Credits'}]], 'one_time_keyboard': True, 'resize_keyboard': True}

@bot.command(r"^\/(help|start)(\s*$|@WolfeLegacyBB?ot)") # Don't match commands aimed at other bots
async def welcome(chat, match):
	await chat.send_sticker(sticker="BQADAwADAgADZUASA3hbI2mGeTbkAg")
	await chat.send_text("\
		Hello, welcome to WolfeBot. This bot is not completely stable yet, so don't be alarmed if it stops working for a bit!\n\n\
		For further info please visit the channel @WolfeBotNews\n\
		Bug reports and feature requests ==> https://github.com/TNTINC/WolfeBot/issues \n\
		If it goes absolutely haywire, throw a line at @icefla",
	parse_mode="HTML")
	return

@bot.command(r'^\/debugdump')
async def dump(chat, match):
	dbsize = len(con.execute("SELECT id FROM media").fetchall())
	db_amount_not_approved = len(
		con.execute("SELECT id FROM media WHERE approved = 0")
		.fetchall()
	)
	my_id = (await bot.get_me())["id"]

	# uptime
	m, s = divmod(time.time() - START_TIME, 60)
	h, m = divmod(m, 60)
	uptime_string = "%d:%02d:%02d" % (h, m, s)

	dump = \
	"""
	-- {time} --
	Wolfe {vs}
	{dbsize} images in database, {db_amount_not_approved} not approved.
	My id is {my_id}. Uptime is: {uptime}.
	{reqnum} requests handled.
	""".format(
		time = time.strftime("%a, %d %b %Y %H:%M:%S UTC"),
		vs = vs,
		dbsize = dbsize,
		db_amount_not_approved = db_amount_not_approved,
		my_id = my_id,
		uptime = uptime_string,
		reqnum = REQNUM
	)
	return chat.reply(dump)

@bot.command(r'^fml')
def weather(chat, match):
	return chat.reply('*fucks your life*')

# Roleplay (owo)
@bot.command(r'\*(.+)\*')
def roleplay(chat, match):
	if 'reply_to_message' in chat.message and chat.message['reply_to_message']['from']['id'] == 194903852:
		global REQNUM
		REQNUM += 1
		return chat.reply("*%s*" % text_model.make_short_sentence(200, tries=200).strip(" .*"))

# Respond to OwO appropriately
@bot.command(r'^OwO')
def owo(chat, match):
	owo = ['whats this??', '*notices ur buldge*', '>//w//<', '*pounces on u*', '*sneaks in your bed and cuddles u*', '*nozzles u*', '*pounces on u and sinks his nozzle inside your fluffy fur*', '*scratches ur ears* x3']
	global REQNUM
	REQNUM += 1
	return chat.send_text(random.choice(owo))

# just why
@bot.command(r'^wolfe sieg')
def owo(chat, match):
	owo = ['What the fuck is wrong with you', 'No.', 'Can we stop please?', 'Is it really necessary?','What about you stop?', 'WHY', 'I wish I didn\'t read tbh.', 'Uh, okay, i guess', 'No, no NO NO NO', 'I\'d rather not reply', 'Hitler was overrated tbh', 'True story bro']
	global REQNUM
	REQNUM += 1
	return chat.send_text(random.choice(owo))

# Stand up for self
@bot.command(r'^wolfe kys')
def owo(chat, match):
	owo = ['No u', 'u', 'no', 'consider suicide', 'How can i kill myself if i\'m a bunch of bits?', 'why would i', 'i see no reason', 'uhm', 'thats okay', 'ehm', 'your fake and gay']
	global REQNUM
	REQNUM += 1
	return chat.send_text(random.choice(owo))

# Query the database for an image and send it
@bot.command(r'\/?yiff\s*$')
async def yiff(chat, match):
	"""
	Send a random approved image from the database.
	"""
	global REQNUM
	REQNUM += 1

	r = con.execute('SELECT path, tg_id, id FROM media WHERE approved = 1 ORDER BY random() LIMIT 1').fetchone()

	keyboard = {'inline_keyboard': [[{'text': '👍', 'callback_data': 'lke_%s' % r[2]},{'text': '👎', 'callback_data': 'dke_%s' % r[2]},{'text': '❤ Fav', 'callback_data': 'fav_%s' % r[2]}]]}

	# No need to reupload if image was already uploaded
	if r[1]:
		try:
			res = await chat.send_photo(photo=r[1]) #, reply_markup=json.dumps(keyboard))
		except RuntimeError:
			print("Failed sending cached image %s" % r[0])
		else:
			return

	with open("%s%s" % (RES_FOLDER, r[0]), 'rb') as f:
		tres = await chat.send_photo(f) #, reply_markup=json.dumps(keyboard))

	if tres['ok']:
		con.execute('UPDATE media SET tg_id = ? WHERE path = ?', (tres['result']['photo'][-1]['file_id'], r[0]))
		con.commit()

# If someone replies "fullsize" to an image we've sent, send the full image uncompressed
@bot.command(r'^(\/?)fullsize')
async def fullsize(chat, match):
	"""
	Send the full version of an image
	"""
	global REQNUM
	REQNUM += 1
	if 'reply_to_message' in chat.message and 'photo' in chat.message['reply_to_message']:
		pid = chat.message['reply_to_message']['photo'][-1]['file_id']

		res = con.execute('SELECT path FROM media WHERE tg_id = ?', (pid,)).fetchone()
		if res:
			with open("%s%s" % (RES_FOLDER, res[0]), 'rb') as f:
				a = await chat.send_document(f, caption='Here you go!')
	return

# Flag an image for moderation
@bot.command(r'^(\/?)delete')
def disapprove(chat, match):
	"""
	Flag an image for moderation.

	Delete the image message, set the approved status of it to 0 in the database and notify @icefla.
	"""
	if 'reply_to_message' in chat.message \
		and 'photo' in chat.message["reply_to_message"]:
		pid = chat.message['reply_to_message']['photo'][-1]['file_id']
		res = con.execute('SELECT path, id FROM media WHERE tg_id = ?', (pid,)).fetchone()
		if res:
			print('[WARN] Soft deleting %s !!!' % res[0])
			chat.reply("Deleting...")

			# Delete the message
			bot.api_call("deleteMessage",
				chat_id = chat.message["chat"]["id"],
				message_id = chat.message["reply_to_message"]["message_id"]
			)

			# Set the photo's approved state to false
			con.execute(
				'UPDATE media SET approved = 0 WHERE tg_id = ?',
				(pid,)
			)
			con.commit()

			# Notify @icefla
			bot.api_call("sendMessage",
				text="Something was flagged! : %s : %s" % (res[1],res[0]),
				chat_id="-262778980"
			)

		else:
			return chat.reply('This image doesn\'t exist!')

@bot.command("/id (.?)$")
def send_image_by_id(chat, match):
	try:
		photo_id = int(match[1])
	except:
		return

	r = con.execute(
		'SELECT tg_id, path FROM media WHERE id = ?',
		(photo_id,)
	).fetchone()

	if r:

		tg_id = r[0]
		path = r[1]

		try:
			print("Sent photo %s from cache" % match[1])
			return chat.send_photo(photo=tg_id)
		except:
			print("Sent photo %s from disk" % match[1])
			return chat.send_photo("%s%s" % (RES_FOLDER,path))
	else:
		return chat.reply("Image not found")

# wolfe yiff me
@bot.command(r'^wolfe (.+) me')
def roleplay(chat, match):
	global REQNUM
	REQNUM += 1
	return chat.send_text('*%ss %s*' % (match.group(1), chat.message['from']['first_name']))

# <3
@bot.command('who\'s keo?')
def keo(chat, match):
	return chat.send_text('A really really cute fox!')

# Praise the bulge
@bot.command('bulge')
def bulge(chat, match):
	if 'reply_to_message' in chat.message and chat.message['reply_to_message']['from']['id'] == 194903852:
		keyboard = {'inline_keyboard': [[{'text': '🍆', 'url': 'https://t.me/bulge'},{'text': '🍆', 'url': 'https://t.me/bulge'},{'text': '🍆', 'url': 'https://t.me/bulge'},{'text': '🍆', 'url': 'https://t.me/bulge'},{'text': '🍆', 'url': 'https://t.me/bulge'}]]}
		return chat.send_text(random.choice(['Did someone say bulge?','*notices your buldge*', 'OwO', 'Murr~', 'Bulge?', 'I happen to have a lot of bulges.']), reply_markup=json.dumps(keyboard))

@bot.inline
def inline(request):
	r = con.execute(
		'SELECT tg_id, id FROM media WHERE tg_id IS NOT NULL AND approved = 1 '
		'ORDER BY random() LIMIT 25'
	).fetchall()
	global REQNUM
	REQNUM += 1
	return request.answer(
		results=
			[{
				'type': 'photo',
				'id': str(pic[1]),
				'photo_file_id': pic[0]
			} for pic in r],
		cache_time=0,
		is_personal=True,
		next_offset='Yolo'
	)

if __name__ == '__main__':
	bot.run()

<|endoftext|>


<commit_before>"""A pure Python package providing the core RDF constructs.

The packages is intended to provide the core RDF types and interfaces
for working with RDF. The package defines a plugin interface for
parsers, stores, and serializers that other packages can use to
implement parsers, stores, and serializers that will plug into the
rdflib package.

The primary interface `rdflib` exposes to work with RDF is
`rdflib.graph.Graph`.

A tiny example:

    >>> from rdflib import Graph, URIRef, Literal

    >>> g = Graph()
    >>> result = g.parse("http://www.w3.org/2000/10/swap/test/meet/blue.rdf")

    >>> print("graph has %s statements." % len(g))
    graph has 4 statements.
    >>>
    >>> for s, p, o in g:
    ...     if (s, p, o) not in g:
    ...         raise Exception("It better be!")

    >>> s = g.serialize(format='nt')
    >>>
    >>> sorted(g) == [
    ...  (URIRef(u'http://meetings.example.com/cal#m1'),
    ...   URIRef(u'http://www.example.org/meeting_organization#homePage'),
    ...   URIRef(u'http://meetings.example.com/m1/hp')),
    ...  (URIRef(u'http://www.example.org/people#fred'),
    ...   URIRef(u'http://www.example.org/meeting_organization#attending'),
    ...   URIRef(u'http://meetings.example.com/cal#m1')),
    ...  (URIRef(u'http://www.example.org/people#fred'),
    ...   URIRef(u'http://www.example.org/personal_details#GivenName'),
    ...   Literal(u'Fred')),
    ...  (URIRef(u'http://www.example.org/people#fred'),
    ...   URIRef(u'http://www.example.org/personal_details#hasEmail'),
    ...   URIRef(u'mailto:fred@example.com'))
    ... ]
    True

"""
__docformat__ = "restructuredtext en"

# The format of the __version__ line is matched by a regex in setup.py
__version__ = "4.2.2-dev"
__date__ = "2015/08/12"

__all__ = [
    'URIRef',
    'BNode',
    'Literal',
    'Variable',

    'Namespace',

    'Dataset',
    'Graph',
    'ConjunctiveGraph',

    'RDF',
    'RDFS',
    'OWL',
    'XSD',

    'util',
]

import sys
assert sys.version_info >= (2, 5, 0), "rdflib requires Python 2.5 or higher"
del sys

import logging
try:
    import __main__
    if not hasattr(__main__, '__file__'):
        # show log messages in interactive mode
        logging.basicConfig(level=logging.INFO)
except ImportError:
    #Main already imported from elsewhere
    import warnings
    warnings.warn('__main__ already imported', ImportWarning)
    del warnings

logger = logging.getLogger(__name__)
logger.info("RDFLib Version: %s" % __version__)

try:
    unichr(0x10FFFF)
except ValueError:
    import warnings
    warnings.warn(
        'You are using a narrow Python build!\n'
        'This means that your Python does not properly support chars > 16bit.\n'
        'On your system chars like c=u"\\U0010FFFF" will have a len(c)==2.\n'
        'As this can cause hard to debug problems with string processing\n'
        '(slicing, regexp, ...) later on, we strongly advise to use a wide\n'
        'Python build in production systems.',
        ImportWarning)
    del warnings

NORMALIZE_LITERALS = True
"""
If True - Literals lexical forms are normalized when created.
I.e. the lexical forms is parsed according to data-type, then the
stored lexical form is the re-serialized value that was parsed.

Illegal values for a datatype are simply kept.  The normalized keyword
for Literal.__new__ can override this.

For example:

>>> from rdflib import Literal,XSD
>>> Literal("01", datatype=XSD.int)
rdflib.term.Literal(u'1', datatype=rdflib.term.URIRef(u'http://www.w3.org/2001/XMLSchema#integer'))

This flag may be changed at any time, but will only affect literals
created after that time, previously created literals will remain
(un)normalized.

"""

DAWG_LITERAL_COLLATION = False
"""
DAWG_LITERAL_COLLATION determines how literals are ordered or compared
to each other.

In SPARQL, applying the >,<,>=,<= operators to literals of
incompatible data-types is an error, i.e:

Literal(2)>Literal('cake') is neither true nor false, but an error.

This is a problem in PY3, where lists of Literals of incompatible
types can no longer be sorted.

Setting this flag to True gives you strict DAWG/SPARQL compliance,
setting it to False will order Literals with incompatible datatypes by
datatype URI

In particular, this determines how the rich comparison operators for
Literal work, eq, __neq__, __lt__, etc.
"""

from rdflib.term import (
    URIRef, BNode, Literal, Variable)

from rdflib.namespace import Namespace

from rdflib.graph import Dataset, Graph, ConjunctiveGraph

from rdflib.namespace import RDF, RDFS, OWL, XSD

from rdflib import plugin
from rdflib import query
# tedious sop to flake8
assert plugin
assert query

from rdflib import util
<commit_msg>Remove logger output<commit_after>"""A pure Python package providing the core RDF constructs.

The packages is intended to provide the core RDF types and interfaces
for working with RDF. The package defines a plugin interface for
parsers, stores, and serializers that other packages can use to
implement parsers, stores, and serializers that will plug into the
rdflib package.

The primary interface `rdflib` exposes to work with RDF is
`rdflib.graph.Graph`.

A tiny example:

    >>> from rdflib import Graph, URIRef, Literal

    >>> g = Graph()
    >>> result = g.parse("http://www.w3.org/2000/10/swap/test/meet/blue.rdf")

    >>> print("graph has %s statements." % len(g))
    graph has 4 statements.
    >>>
    >>> for s, p, o in g:
    ...     if (s, p, o) not in g:
    ...         raise Exception("It better be!")

    >>> s = g.serialize(format='nt')
    >>>
    >>> sorted(g) == [
    ...  (URIRef(u'http://meetings.example.com/cal#m1'),
    ...   URIRef(u'http://www.example.org/meeting_organization#homePage'),
    ...   URIRef(u'http://meetings.example.com/m1/hp')),
    ...  (URIRef(u'http://www.example.org/people#fred'),
    ...   URIRef(u'http://www.example.org/meeting_organization#attending'),
    ...   URIRef(u'http://meetings.example.com/cal#m1')),
    ...  (URIRef(u'http://www.example.org/people#fred'),
    ...   URIRef(u'http://www.example.org/personal_details#GivenName'),
    ...   Literal(u'Fred')),
    ...  (URIRef(u'http://www.example.org/people#fred'),
    ...   URIRef(u'http://www.example.org/personal_details#hasEmail'),
    ...   URIRef(u'mailto:fred@example.com'))
    ... ]
    True

"""
__docformat__ = "restructuredtext en"

# The format of the __version__ line is matched by a regex in setup.py
__version__ = "4.2.2-dev"
__date__ = "2015/08/12"

__all__ = [
    'URIRef',
    'BNode',
    'Literal',
    'Variable',

    'Namespace',

    'Dataset',
    'Graph',
    'ConjunctiveGraph',

    'RDF',
    'RDFS',
    'OWL',
    'XSD',

    'util',
]

import sys
assert sys.version_info >= (2, 5, 0), "rdflib requires Python 2.5 or higher"
del sys

import logging
try:
    import __main__
    if not hasattr(__main__, '__file__'):
        # show log messages in interactive mode
        logging.basicConfig(level=logging.INFO)
except ImportError:
    #Main already imported from elsewhere
    import warnings
    warnings.warn('__main__ already imported', ImportWarning)
    del warnings

try:
    unichr(0x10FFFF)
except ValueError:
    import warnings
    warnings.warn(
        'You are using a narrow Python build!\n'
        'This means that your Python does not properly support chars > 16bit.\n'
        'On your system chars like c=u"\\U0010FFFF" will have a len(c)==2.\n'
        'As this can cause hard to debug problems with string processing\n'
        '(slicing, regexp, ...) later on, we strongly advise to use a wide\n'
        'Python build in production systems.',
        ImportWarning)
    del warnings

NORMALIZE_LITERALS = True
"""
If True - Literals lexical forms are normalized when created.
I.e. the lexical forms is parsed according to data-type, then the
stored lexical form is the re-serialized value that was parsed.

Illegal values for a datatype are simply kept.  The normalized keyword
for Literal.__new__ can override this.

For example:

>>> from rdflib import Literal,XSD
>>> Literal("01", datatype=XSD.int)
rdflib.term.Literal(u'1', datatype=rdflib.term.URIRef(u'http://www.w3.org/2001/XMLSchema#integer'))

This flag may be changed at any time, but will only affect literals
created after that time, previously created literals will remain
(un)normalized.

"""

DAWG_LITERAL_COLLATION = False
"""
DAWG_LITERAL_COLLATION determines how literals are ordered or compared
to each other.

In SPARQL, applying the >,<,>=,<= operators to literals of
incompatible data-types is an error, i.e:

Literal(2)>Literal('cake') is neither true nor false, but an error.

This is a problem in PY3, where lists of Literals of incompatible
types can no longer be sorted.

Setting this flag to True gives you strict DAWG/SPARQL compliance,
setting it to False will order Literals with incompatible datatypes by
datatype URI

In particular, this determines how the rich comparison operators for
Literal work, eq, __neq__, __lt__, etc.
"""

from rdflib.term import (
    URIRef, BNode, Literal, Variable)

from rdflib.namespace import Namespace

from rdflib.graph import Dataset, Graph, ConjunctiveGraph

from rdflib.namespace import RDF, RDFS, OWL, XSD

from rdflib import plugin
from rdflib import query
# tedious sop to flake8
assert plugin
assert query

from rdflib import util
<|endoftext|>


<commit_before>#!/usr/bin/env python3
"""
benchbuild's run command.

This subcommand executes experiments on a set of user-controlled projects.
See the output of benchbuild run --help for more information.
"""
import logging
import os
import time

from plumbum import cli

import benchbuild.experiment as experiment
import benchbuild.experiments as experiments
import benchbuild.project as project
import benchbuild.utils.actions as actions
from benchbuild.settings import CFG
from benchbuild.utils import path, progress

LOG = logging.getLogger(__name__)

class BenchBuildRun(cli.Application):
    """Frontend for running experiments in the benchbuild study framework."""

    experiment_names = []
    project_names = []
    group_name = None

    test_full = cli.Flag(
        ["-F", "--full"],
        help="Test all experiments for the project",
        default=False)

    @cli.switch(
        ["-E", "--experiment"],
        str,
        list=True,
        help="Specify experiments to run")
    def set_experiments(self, names):
        self.experiment_names = names

    @cli.switch(
        ["-D", "--description"],
        str,
        help="A description for this experiment run")
    def set_experiment_tag(self, description):
        CFG["experiment_description"] = description

    @cli.switch(
        ["-P", "--project"], str, list=True, help="Specify projects to run")
    def set_projects(self, names):
        self.project_names = names

    list_experiments = cli.Flag(
        ["-L", "--list-experiments"],
        help="List available experiments",
        default=False)

    list_projects = cli.Flag(
        ["-l", "--list"],
        requires=["--experiment"],
        help="List available projects for experiment",
        default=False)

    show_progress = cli.Flag(
        ["--disable-progress"], help="Disable progress bar", default=True)

    show_config = cli.Flag(
        ["-d", "--dump-config"],
        help="Just dump benchbuild's config and exit.",
        default=False)

    store_config = cli.Flag(
        ["-s", "--save-config"],
        help="Save benchbuild's configuration.",
        default=False)

    @cli.switch(
        ["-G", "--group"],
        str,
        requires=["--experiment"],
        help="Run a group of projects under the given experiments")
    def set_group(self, group):
        self.group_name = group

    pretend = cli.Flag(['p', 'pretend'], default=False)

    def __maybe_list_experiments(self, exps):
        if not self.list_experiments:
            return

        for exp_cls in exps.values():
            print(exp_cls.NAME)
            docstring = exp_cls.__doc__ or "-- no docstring --"
            print(("    " + docstring))
        exit(0)

    def __maybe_list_projects(self, exps, prjs):
        if not self.list_projects:
            return

        for exp_cls in exps.values():
            exp = exp_cls(projects=prjs)
            print_projects(exp)
        exit(0)

    def __maybe_show_config(self, cfg):
        if not self.show_config:
            return

        print(repr(cfg))
        exit(0)

    def __maybe_store_config(self, cfg):
        if not self.store_config:
            config_path = ".benchbuild.yml"
            cfg.store(config_path)
            print("Storing config in {0}".format(os.path.abspath(config_path)))
            exit(0)

    def __generate_plan(self, exps, prjs, cfg):
        if prjs:
            path.mkdir_interactive(cfg["build_dir"].value())

        for exp_cls in exps.values():
            exp = exp_cls(projects=prjs)
            eactn = actions.Experiment(obj=exp, actions=exp.actions())
            yield eactn

    @staticmethod
    def setup_progress(cfg, num_actions):
        """Setup a progress bar.

        Args:
            cfg: Configuration dictionary.
            num_actions (int): Number of actions in the plan.

        Returns:
            The configured progress bar.
        """
        pg_bar = progress.ProgressBar(
            width=80,
            pg_char='|',
            length=num_actions,
            has_output=cfg["verbosity"].value() > 0,
            body=True,
            timer=False)

        def on_step_end(step, func):
            del step, func
            pg_bar.increment()

        actions.Step.ON_STEP_END.append(on_step_end)
        return pg_bar

    def main(self):
        """Main entry point of benchbuild run."""
        experiment_names = self.experiment_names
        project_names = self.project_names
        group_name = self.group_name

        experiments.discover()
        all_exps = experiment.ExperimentRegistry.experiments

        if self.test_full:
            exps = all_exps
        else:
            exps = dict(
                filter(lambda pair: pair[0] in set(experiment_names),
                       all_exps.items()))

        unknown_exps = list(
            filter(lambda name: name not in all_exps.keys(),
                   set(experiment_names)))
        if unknown_exps:
            print('Could not find ', str(unknown_exps),
                  ' in the experiment registry.')
        prjs = project.populate(project_names, group_name)

        self.__maybe_list_experiments(all_exps)
        self.__maybe_list_projects(exps, prjs)
        self.__maybe_show_config(CFG)

        if not experiment_names:
            print("No experiment selected. Did you forget to use -E?")

        plan = list(self.__generate_plan(exps, prjs, CFG))
        num_actions = actions.num_steps(plan)
        actions.print_steps(plan)

        if self.pretend:
            exit(0)

        if self.show_progress:
            pg_bar = type(self).setup_progress(CFG, num_actions)
            pg_bar.start()

        start = time.perf_counter()
        failed = execute_plan(plan)
        end = time.perf_counter()

        if self.show_progress:
            pg_bar.done()

        print_summary(num_actions, failed, end - start)
        return len(failed)

def execute_plan(plan):
    """"Execute the plan.

    Args:
        plan (:obj:`list` of :obj:`actions.Step`): The plan we want to execute.

    Returns:
        (:obj:`list` of :obj:`actions.Step`): A list of failed actions.
    """
    results = [action() for action in plan]
    return [result for result in results if actions.step_has_failed(result)]

def print_projects(exp):
    """
    Print a list of projects registered for that experiment.

    Args:
        exp: The experiment to print all projects for.

    """
    grouped_by = {}
    projects = exp.projects
    if not projects:
        print(
            "Your selection didn't include any projects for this experiment.")

    for name in projects:
        prj = projects[name]

        if prj.GROUP not in grouped_by:
            grouped_by[prj.GROUP] = []

        grouped_by[prj.GROUP].append(prj.NAME)

    for name in grouped_by:
        from textwrap import wrap
        print(">> {0}".format(name))
        projects = sorted(grouped_by[name])
        project_paragraph = ""
        for prj in projects:
            project_paragraph += ", {0}".format(prj)
        print("\n".join(
            wrap(
                project_paragraph[2:],
                80,
                break_on_hyphens=False,
                break_long_words=False)))
        print()

def print_summary(num_actions, failed, duration):
    """
    Print a small summary of the executed plan.

    Args:
        num_actions (int): Total size of the executed plan.
        failed (:obj:`list` of :obj:`actions.Step`): List of failed actions.
        duration: Time we spent executing the plan.
    """
    num_failed = len(failed)
    print("""
Summary:
{num_total} actions were in the queue.
{num_failed} actions failed to execute.

This run took: {elapsed_time:8.3f} seconds.
    """.format(
        num_total=num_actions, num_failed=num_failed, elapsed_time=duration))

    if failed:
        print("Failed:")
        for fail in failed:
            print(fail)
<commit_msg>run: provide new version of print_projects<commit_after>#!/usr/bin/env python3
"""
benchbuild's run command.

This subcommand executes experiments on a set of user-controlled projects.
See the output of benchbuild run --help for more information.
"""
import logging
import os
import time

from plumbum import cli

import benchbuild.experiment as experiment
import benchbuild.experiments as experiments
import benchbuild.project as project
import benchbuild.utils.actions as actions
from benchbuild.settings import CFG
from benchbuild.utils import path, progress

LOG = logging.getLogger(__name__)

class BenchBuildRun(cli.Application):
    """Frontend for running experiments in the benchbuild study framework."""

    experiment_names = []
    project_names = []
    group_name = None

    test_full = cli.Flag(
        ["-F", "--full"],
        help="Test all experiments for the project",
        default=False)

    @cli.switch(
        ["-E", "--experiment"],
        str,
        list=True,
        help="Specify experiments to run")
    def set_experiments(self, names):
        self.experiment_names = names

    @cli.switch(
        ["-D", "--description"],
        str,
        help="A description for this experiment run")
    def set_experiment_tag(self, description):
        CFG["experiment_description"] = description

    @cli.switch(
        ["-P", "--project"], str, list=True, help="Specify projects to run")
    def set_projects(self, names):
        self.project_names = names

    list_experiments = cli.Flag(
        ["-L", "--list-experiments"],
        help="List available experiments",
        default=False)

    list_projects = cli.Flag(
        ["-l", "--list"],
        requires=["--experiment"],
        help="List available projects for experiment",
        default=False)

    show_progress = cli.Flag(
        ["--disable-progress"], help="Disable progress bar", default=True)

    show_config = cli.Flag(
        ["-d", "--dump-config"],
        help="Just dump benchbuild's config and exit.",
        default=False)

    store_config = cli.Flag(
        ["-s", "--save-config"],
        help="Save benchbuild's configuration.",
        default=False)

    @cli.switch(
        ["-G", "--group"],
        str,
        requires=["--experiment"],
        help="Run a group of projects under the given experiments")
    def set_group(self, group):
        self.group_name = group

    pretend = cli.Flag(['p', 'pretend'], default=False)

    def __maybe_list_experiments(self, exps):
        if not self.list_experiments:
            return

        for exp_cls in exps.values():
            print(exp_cls.NAME)
            docstring = exp_cls.__doc__ or "-- no docstring --"
            print(("    " + docstring))
        exit(0)

    def __maybe_list_projects(self, exps, prjs):
        if not self.list_projects:
            return

        for exp_cls in exps.values():
            exp = exp_cls(projects=prjs)
            print_projects(exp)
        exit(0)

    def __maybe_show_config(self, cfg):
        if not self.show_config:
            return

        print(repr(cfg))
        exit(0)

    def __maybe_store_config(self, cfg):
        if not self.store_config:
            config_path = ".benchbuild.yml"
            cfg.store(config_path)
            print("Storing config in {0}".format(os.path.abspath(config_path)))
            exit(0)

    def __generate_plan(self, exps, prjs, cfg):
        if prjs:
            path.mkdir_interactive(cfg["build_dir"].value())

        for exp_cls in exps.values():
            exp = exp_cls(projects=prjs)
            eactn = actions.Experiment(obj=exp, actions=exp.actions())
            yield eactn

    @staticmethod
    def setup_progress(cfg, num_actions):
        """Setup a progress bar.

        Args:
            cfg: Configuration dictionary.
            num_actions (int): Number of actions in the plan.

        Returns:
            The configured progress bar.
        """
        pg_bar = progress.ProgressBar(
            width=80,
            pg_char='|',
            length=num_actions,
            has_output=cfg["verbosity"].value() > 0,
            body=True,
            timer=False)

        def on_step_end(step, func):
            del step, func
            pg_bar.increment()

        actions.Step.ON_STEP_END.append(on_step_end)
        return pg_bar

    def main(self):
        """Main entry point of benchbuild run."""
        experiment_names = self.experiment_names
        project_names = self.project_names
        group_name = self.group_name

        experiments.discover()
        all_exps = experiment.ExperimentRegistry.experiments

        if self.test_full:
            exps = all_exps
        else:
            exps = dict(
                filter(lambda pair: pair[0] in set(experiment_names),
                       all_exps.items()))

        unknown_exps = list(
            filter(lambda name: name not in all_exps.keys(),
                   set(experiment_names)))
        if unknown_exps:
            print('Could not find ', str(unknown_exps),
                  ' in the experiment registry.')
        prjs = project.populate(project_names, group_name)

        self.__maybe_list_experiments(all_exps)
        self.__maybe_list_projects(exps, prjs)
        self.__maybe_show_config(CFG)

        if not experiment_names:
            print("No experiment selected. Did you forget to use -E?")

        plan = list(self.__generate_plan(exps, prjs, CFG))
        num_actions = actions.num_steps(plan)
        actions.print_steps(plan)

        if self.pretend:
            exit(0)

        if self.show_progress:
            pg_bar = type(self).setup_progress(CFG, num_actions)
            pg_bar.start()

        start = time.perf_counter()
        failed = execute_plan(plan)
        end = time.perf_counter()

        if self.show_progress:
            pg_bar.done()

        print_summary(num_actions, failed, end - start)
        return len(failed)

def execute_plan(plan):
    """"Execute the plan.

    Args:
        plan (:obj:`list` of :obj:`actions.Step`): The plan we want to execute.

    Returns:
        (:obj:`list` of :obj:`actions.Step`): A list of failed actions.
    """
    results = [action() for action in plan]
    return [result for result in results if actions.step_has_failed(result)]

def print_projects(exp):
    """
    Print a list of projects registered for that experiment.

    Args:
        exp: The experiment to print all projects for.

    """
    grouped_by = {}
    projects = exp.projects
    if not projects:
        print(
            "Your selection didn't include any projects for this experiment.")

    for name in projects:
        prj = projects[name]

        if prj.GROUP not in grouped_by:
            grouped_by[prj.GROUP] = []

        grouped_by[prj.GROUP].append("{name}/{group}".format(
            name=prj.NAME, group=prj.GROUP))

    for name in grouped_by:
        print("group: {0}".format(name))
        group_projects = sorted(grouped_by[name])
        for prj in group_projects:
            prj_cls = projects[prj]
            print("  name: {id:<32} {version:<24} {src}".format(
                id="{0}/{1}".format(prj_cls.NAME, prj_cls.GROUP),
                version="version: {0}".format(prj_cls.VERSION),
                src="source: {0}".format(prj_cls.SRC_FILE)))
        print()

def print_summary(num_actions, failed, duration):
    """
    Print a small summary of the executed plan.

    Args:
        num_actions (int): Total size of the executed plan.
        failed (:obj:`list` of :obj:`actions.Step`): List of failed actions.
        duration: Time we spent executing the plan.
    """
    num_failed = len(failed)
    print("""
Summary:
{num_total} actions were in the queue.
{num_failed} actions failed to execute.

This run took: {elapsed_time:8.3f} seconds.
    """.format(
        num_total=num_actions, num_failed=num_failed, elapsed_time=duration))

    if failed:
        print("Failed:")
        for fail in failed:
            print(fail)
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-
###############################################################################
#
# ODOO (ex OpenERP)
# Open Source Management Solution
# Copyright (C) 2001-2015 Micronaet S.r.l. (<http://www.micronaet.it>)
# Developer: Nicola Riolini @thebrush (<https://it.linkedin.com/in/thebrush>)
# 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 os
import sys
import logging
import netsvc
import csv
import decimal_precision as dp
from os import listdir
from osv import fields, osv, expression, orm
from datetime import datetime, timedelta
from tools.translate import _
from tools import (DEFAULT_SERVER_DATE_FORMAT,
    DEFAULT_SERVER_DATETIME_FORMAT,
    DATETIME_FORMATS_MAP,
    )

_logger = logging.getLogger(__name__)

class account_analytic_expense_km(osv.osv):
    ''' Add schedule method and override split method
    '''
    _name = 'account.analytic.expense.km'
    _description = 'Monthly transport km'
    _rec_name = 'account_id'
    _order = 'month'

    # -------------------------------------------------------------------------
    #                          XMLRPC function
    # -------------------------------------------------------------------------
    def schedule_csv_accounting_transport_movement_import(
            self, cr, uid, path='~/etl/transport', separator=';', header=0,
            general_code='410100', context=None):
        ''' Import function that read in:
            path: folder where all transport Km file are
            separator: csv file format have this column separator
            header: and total line header passed
            general_code: general account code
            context: context for this function

            Note: file period are coded in filename
        '''
        from os.path import isfile, join

        # pools used:
        import pdb; pdb.set_trace()
        csv_pool = self.pool.get('csv.base')
        account_pool = self.pool.get('account.account')
        contract_pool = self.pool.get('account.analytic.account')
        line_pool = self.pool.get('account.analytic.line')
        journal_pool = self.pool.get('account.analytic.journal')

        # Read parameters for write analytic enytry:
        # Purchase journal:
        journal_id = journal_pool.get_journal_purchase(
            cr, uid, context=context)

        # Code for entry (ledger) operation:
        general_id = account_pool.get_account_id(
            cr, uid, general_code, context=context)
        if not general_id:
            _logger.error(_('Cannot create analytic line, no ledge!'))
            return False

        # Get file list:
        path = os.path.expanduser(path)
        trans_file = [
            filename for filename in listdir(path) if
                isfile(join(path, filename)) and filename[-3:] == 'csv']

        if not trans_file:
            _logger.warning(
                _('File not found in transport folder: %s') % path)
            return True

        trans_file.sort() # for have last price correct
        _logger.info('Start auto import of file expences')
        for filename in trans_file:
            try:
                _logger.info('Load and import file %s' % filename)

                # ----------------------------------
                # Remove previous import if present:
                # ----------------------------------
                unlink_ids = line_pool.search(cr, uid, [
                    ('csv_filename', '=', filename),
                    ], context=context)
                if unlink_ids:
                    line_pool.unlink(cr, uid, unlink_ids, context=context)
                    _logger.info(
                        'Removed previous costs: %s (file: %s)' % (
                            len(unlink_ids),
                            filename,
                            ))

                # ------------------------------
                # Get data period from filename:
                # ------------------------------
                # Format file: COST|YY|MM|.|csv
                period = filename[:-3][-4:]
                if not period.isdigit():
                    _logger.error(
                        _('%s. Filename syntax error COSTYYMM.csv: %s') % (
                            filename))
                    continue

                period_date = '20%02d-%02d-01' % (
                    period[:2],
                    period[2:],
                    )
                error = []

                i = -header
                fullpath = join(path, filename)
                f = open(fullpath, 'rb')

                parent_id = self.create(cr, uid, {
                    'name': _('Import file: %s') % filename,
                    }, context=context)
                for line in f:
                    i += 1
                    if i <= 0: # jump header line
                        continue
                    line = line.strip().split(separator)

                    # Parse columns:
                    code = csv_pool.decode_string(line[0])
                    amount = csv_pool.decode_float(line[1])

                    # Search contract
                    contract_ids = contract_pool.search(cr, uid, [
                        ('code', '=', code)], context=context)

                    if not contract_ids:
                        _logger.error(
                            _('%s. Code not found on OpenERP: %s') % (i, code))
                        continue

                    elif len(contract_ids) > 1:
                        _logger.error(
                            _('%s. More than one code found (%s): %s') % (
                                i, len(contract_ids), code))
                        continue

                    line_pool.create(cr, uid, {
                        'amount': -amount,
                        'user_id': uid,
                        'name': _('Import: %s') % filename,
                        'unit_amount': 1.0,
                        'account_id': contract_ids[0],
                        'general_account_id': general_id,
                        'journal_id': journal_id,
                        'date': period_date,

                        # Link to import record:
                        'km_import_id': parent_id,
                        'import_filename': filename, # key for deletion

                        # Not used:
                        #'company_id', 'code', 'currency_id', 'move_id',
                        #'product_id', 'product_uom_id', 'amount_currency',
                        #'ref', 'to_invoice', 'invoice_id',
                        # 'extra_analytic_line_timesheet_id', 'import_type',
                        ##'activity_id', 'mail_raccomanded', 'location',
                        }, context=context)
                f.close()

                # History file:
                os.rename(
                    os.path.join(path, filename),
                    os.path.join(path, 'history', '%s.%s' % (
                        datetime.now().strftime('%Y%m%d.%H%M%S'),
                        filename, )),
                    )

                # TODO write error in file
                if error:
                    self.write(cr, uid, parent_id, {
                        'error': '\n'.join(error)}, context=context)
            except:
                _logger.error('No correct file format: %s' % filename)
                _logger.error((sys.exc_info(), ))

        _logger.info('End auto import of file transport')
        return True

    # XXX OLD PROCEDURE FOR IMPORT MOVEMENT FILES NOW REPLATED WITH
    # FILENAME WITH PERIOD CODED
    """
    def schedule_csv_accounting_transport_movement_import(
            self, cr, uid, path='~/etl/transport', separator=';', header=0,
            general_code='410100', from_month=9, context=None):
        ''' Import function that read in:
            path: folder where all transport Km file are
            separator: csv file format have this column separator
            header: and total line header passed
            general_code: general account code
            from_month: number of colum for import extra discount
            context: context for this function
        '''
        from os.path import isfile, join

        # pools used:
        csv_pool = self.pool.get('csv.base')
        account_pool = self.pool.get('account.account')
        contract_pool = self.pool.get('account.analytic.account')
        line_pool = self.pool.get('account.analytic.line')
        journal_pool = self.pool.get('account.analytic.journal')

        # Read paramters for write analytic enytry:
        # Purchase journal:
        journal_id = journal_pool.get_journal_purchase(
            cr, uid, context=context)

        # Code for entry (ledger) operation:
        general_id = account_pool.get_account_id(
            cr, uid, general_code, context=context)
        if not general_id:
            _logger.error(_('Cannot create analytic line, no ledge!'))
            return False

        # Get file list:
        path = os.path.expanduser(path)
        trans_file = [
            filename for filename in listdir(path) if
                isfile(join(path, filename)) and filename[-3:] == 'csv']

        if not trans_file:
            _logger.warning(_('File not found in transport folder: %s') % path)
            return True

        trans_file.sort() # for have last price correct
        _logger.info("Start auto import of file transport")
        for filename in trans_file:
            try:
                _logger.info("Load and import file %s" % filename)
                error = []

                i = -header
                fullpath = join(path, filename)
                f = open(fullpath, 'rb')

                parent_id = self.create(cr, uid, {
                    'name': _('Import file: %s') % filename,
                    }, context=context)
                for line in f:
                    i += 1
                    if i <= 0: # jump header line
                        continue
                    line = line.strip().split(separator)

                    code = csv_pool.decode_string(line[0])
                    # Search contract
                    contract_ids = contract_pool.search(cr, uid, [
                        ('code', '=', code)], context=context)

                    if not contract_ids:
                        _logger.error(
                            _('%s. Code not found on OpenERP: %s') % (i, code))
                        continue

                    elif len(contract_ids) > 1:
                        _logger.error(
                            _('%s. More than one code found (%s): %s') % (
                                i, len(contract_ids), code))
                        continue

                    for i in range(from_month, len(line)):
                        amount = csv_pool.decode_float(line[i])

                        line_pool.create(cr, uid, {
                            'amount': -amount,
                            'user_id': uid,
                            'name': _('Import: %s') % filename, # TODO
                            'unit_amount': 1.0,
                            'account_id': contract_ids[0],
                            'general_account_id': general_id,
                            'journal_id': journal_id,
                            'date': '2015-%02d-01' % i, # TODO

                            # Link to import record:
                            'km_import_id': parent_id,

                            # Not used:
                            #'company_id', 'code', 'currency_id', 'move_id',
                            #'product_id', 'product_uom_id', 'amount_currency',
                            #'ref', 'to_invoice', 'invoice_id',
                            # 'extra_analytic_line_timesheet_id', 'import_type',
                            ##'activity_id', 'mail_raccomanded', 'location',
                            }, context=context)
                f.close()

                # History file:
                os.rename(
                    os.path.join(path, filename),
                    os.path.join(path, 'history', '%s.%s' % (
                        datetime.now().strftime('%Y%m%d.%H%M%S'),
                        filename, )),
                    )

                # TODO write error in file
                if error:
                    self.write(cr, uid, parent_id, {
                        'error': '\n'.join(error)}, context=context)
            except:
                _logger.error('No correct file format: %s' % filename)
                _logger.error((sys.exc_info(), ))

        _logger.info("End auto import of file transport")
        return True"""

    _columns = {
        'name': fields.char('Import', size=120, required=True),
        'datetime': fields.date('Import date'),
        'error': fields.text('Error'),
         }

    _defaults = {
        'datetime': lambda *x: datetime.now().strftime(
            DEFAULT_SERVER_DATETIME_FORMAT),
        }
account_analytic_expense_km()

class account_analytic_line(osv.osv):
    ''' Extra fields for analytic line
    '''
    _inherit = 'account.analytic.line'

    _columns = {
        'km_import_id': fields.many2one(
            'account.analytic.expense.km', 'Import Km', ondelete='cascade'),
        'csv_filename': fields.char('CSV filename', size=80),
        }
account_analytic_line()

class account_analytic_expense_km(osv.osv):
    ''' Add schedule method and override split method
    '''
    _inherit = 'account.analytic.expense.km'

    _columns = {
        'line_ids': fields.one2many(
            'account.analytic.line', 'km_import_id', 'Analytic line'),
        }

account_analytic_expense_km()
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
<commit_msg>Add log<commit_after># -*- coding: utf-8 -*-
###############################################################################
#
# ODOO (ex OpenERP)
# Open Source Management Solution
# Copyright (C) 2001-2015 Micronaet S.r.l. (<http://www.micronaet.it>)
# Developer: Nicola Riolini @thebrush (<https://it.linkedin.com/in/thebrush>)
# 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 os
import sys
import logging
import netsvc
import csv
import decimal_precision as dp
from os import listdir
from osv import fields, osv, expression, orm
from datetime import datetime, timedelta
from tools.translate import _
from tools import (DEFAULT_SERVER_DATE_FORMAT,
    DEFAULT_SERVER_DATETIME_FORMAT,
    DATETIME_FORMATS_MAP,
    )

_logger = logging.getLogger(__name__)

class account_analytic_expense_km(osv.osv):
    ''' Add schedule method and override split method
    '''
    _name = 'account.analytic.expense.km'
    _description = 'Monthly transport km'
    _rec_name = 'account_id'
    _order = 'month'

    # -------------------------------------------------------------------------
    #                          XMLRPC function
    # -------------------------------------------------------------------------
    def schedule_csv_accounting_transport_movement_import(
            self, cr, uid, path='~/etl/transport', separator=';', header=0,
            general_code='410100', context=None):
        ''' Import function that read in:
            path: folder where all transport Km file are
            separator: csv file format have this column separator
            header: and total line header passed
            general_code: general account code
            context: context for this function

            Note: file period are coded in filename
        '''
        from os.path import isfile, join

        # pools used:
        csv_pool = self.pool.get('csv.base')
        account_pool = self.pool.get('account.account')
        contract_pool = self.pool.get('account.analytic.account')
        line_pool = self.pool.get('account.analytic.line')
        journal_pool = self.pool.get('account.analytic.journal')

        # Read parameters for write analytic enytry:
        # Purchase journal:
        journal_id = journal_pool.get_journal_purchase(
            cr, uid, context=context)

        # Code for entry (ledger) operation:
        general_id = account_pool.get_account_id(
            cr, uid, general_code, context=context)
        if not general_id:
            _logger.error(_('Cannot create analytic line, no ledge!'))
            return False

        # Get file list:
        path = os.path.expanduser(path)
        trans_file = [
            filename for filename in listdir(path) if
                isfile(join(path, filename)) and filename[-3:] == 'csv']

        if not trans_file:
            _logger.warning(
                _('File not found in transport folder: %s') % path)
            return True

        trans_file.sort() # for have last price correct
        _logger.info('Start auto import of file expences')
        import pdb; pdb.set_trace()
        for filename in trans_file:
            try:
                _logger.info('Load and import file %s' % filename)
                error = [] # from here log error

                # ----------------------------------
                # Remove previous import if present:
                # ----------------------------------
                unlink_ids = line_pool.search(cr, uid, [
                    ('csv_filename', '=', filename),
                    ], context=context)
                if unlink_ids:
                    line_pool.unlink(cr, uid, unlink_ids, context=context)
                    _logger.info(
                        'Removed previous costs: %s (file: %s)' % (
                            len(unlink_ids),
                            filename,
                            ))

                # ------------------------------
                # Get data period from filename:
                # ------------------------------
                # Format file: COST|YY|MM|.|csv
                period = filename[-8:-4]
                if not period.isdigit():
                    error.append(
                        _('%s. Filename syntax error COSTYYMM.csv: %s') % (
                            filename))
                    _logger.error(error[-1])
                    continue

                period_date = '20%s-%s-01' % (
                    period[:2],
                    period[2:],
                    )

                i = -header
                fullpath = join(path, filename)
                f = open(fullpath, 'rb')

                parent_id = self.create(cr, uid, {
                    'name': _('Import file: %s') % filename,
                    }, context=context)
                for line in f:
                    i += 1
                    if i <= 0: # jump header line
                        continue
                    line = line.strip().split(separator)

                    # Parse columns:
                    code = csv_pool.decode_string(line[0])
                    amount = csv_pool.decode_float(line[1])

                    if not code:
                        error.append(_('%s. Contract code empty') % i)
                        _logger.error(error[-1])

                    # Search contract
                    contract_ids = contract_pool.search(cr, uid, [
                        ('code', '=', code)], context=context)

                    if not contract_ids:
                        error.append(
                            _('%s. Contract not found on OpenERP: %s') % (
                                i, code))
                        _logger.error(error[-1])
                        continue

                    elif len(contract_ids) > 1:
                        error.append(
                            _('%s. More than one contract found (%s): %s') % (
                                i, len(contract_ids), code))
                        _logger.error(error[-1])
                        continue

                    line_pool.create(cr, uid, {
                        'amount': -amount,
                        'user_id': uid,
                        'name': _('Import: %s') % filename,
                        'unit_amount': 1.0,
                        'account_id': contract_ids[0],
                        'general_account_id': general_id,
                        'journal_id': journal_id,
                        'date': period_date,

                        # Link to import record:
                        'km_import_id': parent_id,
                        'import_filename': filename, # key for deletion

                        # Not used:
                        #'company_id', 'code', 'currency_id', 'move_id',
                        #'product_id', 'product_uom_id', 'amount_currency',
                        #'ref', 'to_invoice', 'invoice_id',
                        # 'extra_analytic_line_timesheet_id', 'import_type',
                        ##'activity_id', 'mail_raccomanded', 'location',
                        }, context=context)
                f.close()

                # History file:
                os.rename(
                    os.path.join(path, filename),
                    os.path.join(path, 'history', '%s.%s' % (
                        datetime.now().strftime('%Y%m%d.%H%M%S'),
                        filename, )),
                    )

                # TODO write error in file
                if error:
                    self.write(cr, uid, parent_id, {
                        'error': '\n'.join(error)}, context=context)
            except:
                _logger.error('No correct file format: %s' % filename)
                error.append('%s' % ((sys.exc_info(), )))
                _logger.error(error[-1])

        _logger.info('End auto import of file transport')
        return True

    # XXX OLD PROCEDURE FOR IMPORT MOVEMENT FILES NOW REPLATED WITH
    # FILENAME WITH PERIOD CODED
    """
    def schedule_csv_accounting_transport_movement_import(
            self, cr, uid, path='~/etl/transport', separator=';', header=0,
            general_code='410100', from_month=9, context=None):
        ''' Import function that read in:
            path: folder where all transport Km file are
            separator: csv file format have this column separator
            header: and total line header passed
            general_code: general account code
            from_month: number of colum for import extra discount
            context: context for this function
        '''
        from os.path import isfile, join

        # pools used:
        csv_pool = self.pool.get('csv.base')
        account_pool = self.pool.get('account.account')
        contract_pool = self.pool.get('account.analytic.account')
        line_pool = self.pool.get('account.analytic.line')
        journal_pool = self.pool.get('account.analytic.journal')

        # Read paramters for write analytic enytry:
        # Purchase journal:
        journal_id = journal_pool.get_journal_purchase(
            cr, uid, context=context)

        # Code for entry (ledger) operation:
        general_id = account_pool.get_account_id(
            cr, uid, general_code, context=context)
        if not general_id:
            _logger.error(_('Cannot create analytic line, no ledge!'))
            return False

        # Get file list:
        path = os.path.expanduser(path)
        trans_file = [
            filename for filename in listdir(path) if
                isfile(join(path, filename)) and filename[-3:] == 'csv']

        if not trans_file:
            _logger.warning(_('File not found in transport folder: %s') % path)
            return True

        trans_file.sort() # for have last price correct
        _logger.info("Start auto import of file transport")
        for filename in trans_file:
            try:
                _logger.info("Load and import file %s" % filename)
                error = []

                i = -header
                fullpath = join(path, filename)
                f = open(fullpath, 'rb')

                parent_id = self.create(cr, uid, {
                    'name': _('Import file: %s') % filename,
                    }, context=context)
                for line in f:
                    i += 1
                    if i <= 0: # jump header line
                        continue
                    line = line.strip().split(separator)

                    code = csv_pool.decode_string(line[0])
                    # Search contract
                    contract_ids = contract_pool.search(cr, uid, [
                        ('code', '=', code)], context=context)

                    if not contract_ids:
                        _logger.error(
                            _('%s. Code not found on OpenERP: %s') % (i, code))
                        continue

                    elif len(contract_ids) > 1:
                        _logger.error(
                            _('%s. More than one code found (%s): %s') % (
                                i, len(contract_ids), code))
                        continue

                    for i in range(from_month, len(line)):
                        amount = csv_pool.decode_float(line[i])

                        line_pool.create(cr, uid, {
                            'amount': -amount,
                            'user_id': uid,
                            'name': _('Import: %s') % filename, # TODO
                            'unit_amount': 1.0,
                            'account_id': contract_ids[0],
                            'general_account_id': general_id,
                            'journal_id': journal_id,
                            'date': '2015-%02d-01' % i, # TODO

                            # Link to import record:
                            'km_import_id': parent_id,

                            # Not used:
                            #'company_id', 'code', 'currency_id', 'move_id',
                            #'product_id', 'product_uom_id', 'amount_currency',
                            #'ref', 'to_invoice', 'invoice_id',
                            # 'extra_analytic_line_timesheet_id', 'import_type',
                            ##'activity_id', 'mail_raccomanded', 'location',
                            }, context=context)
                f.close()

                # History file:
                os.rename(
                    os.path.join(path, filename),
                    os.path.join(path, 'history', '%s.%s' % (
                        datetime.now().strftime('%Y%m%d.%H%M%S'),
                        filename, )),
                    )

                # TODO write error in file
                if error:
                    self.write(cr, uid, parent_id, {
                        'error': '\n'.join(error)}, context=context)
            except:
                _logger.error('No correct file format: %s' % filename)
                _logger.error((sys.exc_info(), ))

        _logger.info("End auto import of file transport")
        return True"""

    _columns = {
        'name': fields.char('Import', size=120, required=True),
        'datetime': fields.date('Import date'),
        'error': fields.text('Error'),
         }

    _defaults = {
        'datetime': lambda *x: datetime.now().strftime(
            DEFAULT_SERVER_DATETIME_FORMAT),
        }
account_analytic_expense_km()

class account_analytic_line(osv.osv):
    ''' Extra fields for analytic line
    '''
    _inherit = 'account.analytic.line'

    _columns = {
        'km_import_id': fields.many2one(
            'account.analytic.expense.km', 'Import Km', ondelete='cascade'),
        'csv_filename': fields.char('CSV filename', size=80),
        }
account_analytic_line()

class account_analytic_expense_km(osv.osv):
    ''' Add schedule method and override split method
    '''
    _inherit = 'account.analytic.expense.km'

    _columns = {
        'line_ids': fields.one2many(
            'account.analytic.line', 'km_import_id', 'Analytic line'),
        }

account_analytic_expense_km()
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
<|endoftext|>