<commit_before>"""Helpers for components that manage entities."""
import asyncio

from homeassistant import config as conf_util
from homeassistant.bootstrap import (
    async_prepare_setup_platform, async_prepare_setup_component)
from homeassistant.const import (
    ATTR_ENTITY_ID, CONF_SCAN_INTERVAL, CONF_ENTITY_NAMESPACE,
    DEVICE_DEFAULT_NAME)
from homeassistant.core import callback
from homeassistant.exceptions import HomeAssistantError
from homeassistant.loader import get_component
from homeassistant.helpers import config_per_platform, discovery
from homeassistant.helpers.entity import async_generate_entity_id
from homeassistant.helpers.event import async_track_utc_time_change
from homeassistant.helpers.service import extract_entity_ids
from homeassistant.util.async import (
    run_callback_threadsafe, run_coroutine_threadsafe)

DEFAULT_SCAN_INTERVAL = 15

class EntityComponent(object):
    """Helper class that will help a component manage its entities."""

    def __init__(self, logger, domain, hass,
                 scan_interval=DEFAULT_SCAN_INTERVAL, group_name=None):
        """Initialize an entity component."""
        self.logger = logger
        self.hass = hass

        self.domain = domain
        self.entity_id_format = domain + '.{}'
        self.scan_interval = scan_interval
        self.group_name = group_name

        self.entities = {}
        self.group = None

        self.config = None

        self._platforms = {
            'core': EntityPlatform(self, self.scan_interval, None),
        }
        self.async_add_entities = self._platforms['core'].async_add_entities
        self.add_entities = self._platforms['core'].add_entities

    def setup(self, config):
        """Set up a full entity component.

        Loads the platforms from the config and will listen for supported
        discovered platforms.
        """
        run_coroutine_threadsafe(
            self.async_setup(config), self.hass.loop
        ).result()

    @asyncio.coroutine
    def async_setup(self, config):
        """Set up a full entity component.

        Loads the platforms from the config and will listen for supported
        discovered platforms.

        This method must be run in the event loop.
        """
        self.config = config

        # Look in config for Domain, Domain 2, Domain 3 etc and load them
        tasks = []
        for p_type, p_config in config_per_platform(config, self.domain):
            tasks.append(self._async_setup_platform(p_type, p_config))

        yield from asyncio.gather(*tasks, loop=self.hass.loop)

        # Generic discovery listener for loading platform dynamically
        # Refer to: homeassistant.components.discovery.load_platform()
        @callback
        def component_platform_discovered(platform, info):
            """Callback to load a platform."""
            self.hass.loop.create_task(
                self._async_setup_platform(platform, {}, info))

        discovery.async_listen_platform(
            self.hass, self.domain, component_platform_discovered)

    def extract_from_service(self, service, expand_group=True):
        """Extract all known entities from a service call.

        Will return all entities if no entities specified in call.
        Will return an empty list if entities specified but unknown.
        """
        return run_callback_threadsafe(
            self.hass.loop, self.async_extract_from_service, service,
            expand_group
        ).result()

    def async_extract_from_service(self, service, expand_group=True):
        """Extract all known entities from a service call.

        Will return all entities if no entities specified in call.
        Will return an empty list if entities specified but unknown.

        This method must be run in the event loop.
        """
        if ATTR_ENTITY_ID not in service.data:
            return list(self.entities.values())

        return [self.entities[entity_id] for entity_id
                in extract_entity_ids(self.hass, service, expand_group)
                if entity_id in self.entities]

    @asyncio.coroutine
    def _async_setup_platform(self, platform_type, platform_config,
                              discovery_info=None):
        """Setup a platform for this component.

        This method must be run in the event loop.
        """
        platform = yield from async_prepare_setup_platform(
            self.hass, self.config, self.domain, platform_type)

        if platform is None:
            return

        # Config > Platform > Component
        scan_interval = (platform_config.get(CONF_SCAN_INTERVAL) or
                         getattr(platform, 'SCAN_INTERVAL', None) or
                         self.scan_interval)
        entity_namespace = platform_config.get(CONF_ENTITY_NAMESPACE)

        key = (platform_type, scan_interval, entity_namespace)

        if key not in self._platforms:
            self._platforms[key] = EntityPlatform(self, scan_interval,
                                                  entity_namespace)
        entity_platform = self._platforms[key]

        try:
            if getattr(platform, 'async_setup_platform', None):
                yield from platform.async_setup_platform(
                    self.hass, platform_config,
                    entity_platform.async_add_entities, discovery_info
                )
            else:
                yield from self.hass.loop.run_in_executor(
                    None, platform.setup_platform, self.hass, platform_config,
                    entity_platform.add_entities, discovery_info
                )

            self.hass.config.components.append(
                '{}.{}'.format(self.domain, platform_type))
        except Exception:  # pylint: disable=broad-except
            self.logger.exception(
                'Error while setting up platform %s', platform_type)

    def add_entity(self, entity, platform=None, update_before_add=False):
        """Add entity to component."""
        return run_coroutine_threadsafe(
            self.async_add_entity(entity, platform, update_before_add),
            self.hass.loop
        ).result()

    @asyncio.coroutine
    def async_add_entity(self, entity, platform=None, update_before_add=False):
        """Add entity to component.

        This method must be run in the event loop.
        """
        if entity is None or entity in self.entities.values():
            return False

        entity.hass = self.hass

        # update/init entity data
        if update_before_add:
            if hasattr(entity, 'async_update'):
                yield from entity.async_update()
            else:
                yield from self.hass.loop.run_in_executor(None, entity.update)

        if getattr(entity, 'entity_id', None) is None:
            object_id = entity.name or DEVICE_DEFAULT_NAME

            if platform is not None and platform.entity_namespace is not None:
                object_id = '{} {}'.format(platform.entity_namespace,
                                           object_id)

            entity.entity_id = async_generate_entity_id(
                self.entity_id_format, object_id,
                self.entities.keys())

        self.entities[entity.entity_id] = entity
        yield from entity.async_update_ha_state()

        return True

    def update_group(self):
        """Set up and/or update component group."""
        run_callback_threadsafe(
            self.hass.loop, self.async_update_group).result()

    @asyncio.coroutine
    def async_update_group(self):
        """Set up and/or update component group.

        This method must be run in the event loop.
        """
        if self.group is None and self.group_name is not None:
            group = get_component('group')
            self.group = yield from group.Group.async_create_group(
                self.hass, self.group_name, self.entities.keys(),
                user_defined=False
            )
        elif self.group is not None:
            yield from self.group.async_update_tracked_entity_ids(
                self.entities.keys())

    def reset(self):
        """Remove entities and reset the entity component to initial values."""
        run_coroutine_threadsafe(self.async_reset(), self.hass.loop).result()

    @asyncio.coroutine
    def async_reset(self):
        """Remove entities and reset the entity component to initial values.

        This method must be run in the event loop.
        """
        tasks = [platform.async_reset() for platform
                 in self._platforms.values()]

        yield from asyncio.gather(*tasks, loop=self.hass.loop)

        self._platforms = {
            'core': self._platforms['core']
        }
        self.entities = {}
        self.config = None

        if self.group is not None:
            yield from self.group.async_stop()
            self.group = None

    def prepare_reload(self):
        """Prepare reloading this entity component."""
        return run_coroutine_threadsafe(
            self.async_prepare_reload(), loop=self.hass.loop).result()

    @asyncio.coroutine
    def async_prepare_reload(self):
        """Prepare reloading this entity component.

        This method must be run in the event loop.
        """
        try:
            conf = yield from \
                conf_util.async_hass_config_yaml(self.hass)
        except HomeAssistantError as err:
            self.logger.error(err)
            return None

        conf = yield from async_prepare_setup_component(
            self.hass, conf, self.domain)

        if conf is None:
            return None

        yield from self.async_reset()
        return conf

class EntityPlatform(object):
    """Keep track of entities for a single platform and stay in loop."""

    def __init__(self, component, scan_interval, entity_namespace):
        """Initalize the entity platform."""
        self.component = component
        self.scan_interval = scan_interval
        self.entity_namespace = entity_namespace
        self.platform_entities = []
        self._async_unsub_polling = None

    def add_entities(self, new_entities, update_before_add=False):
        """Add entities for a single platform."""
        run_coroutine_threadsafe(
            self.async_add_entities(list(new_entities), update_before_add),
            self.component.hass.loop
        ).result()

    @asyncio.coroutine
    def async_add_entities(self, new_entities, update_before_add=False):
        """Add entities for a single platform async.

        This method must be run in the event loop.
        """
        tasks = [self._async_process_entity(entity, update_before_add)
                 for entity in new_entities]

        yield from asyncio.gather(*tasks, loop=self.component.hass.loop)
        yield from self.component.async_update_group()

        if self._async_unsub_polling is not None or \
           not any(entity.should_poll for entity
                   in self.platform_entities):
            return

        self._async_unsub_polling = async_track_utc_time_change(
            self.component.hass, self._update_entity_states,
            second=range(0, 60, self.scan_interval))

    @asyncio.coroutine
    def _async_process_entity(self, new_entity, update_before_add):
        """Add entities to StateMachine."""
        ret = yield from self.component.async_add_entity(
            new_entity, self, update_before_add=update_before_add
        )
        if ret:
            self.platform_entities.append(new_entity)

    @asyncio.coroutine
    def async_reset(self):
        """Remove all entities and reset data.

        This method must be run in the event loop.
        """
        tasks = [entity.async_remove() for entity in self.platform_entities]

        yield from asyncio.gather(*tasks, loop=self.component.hass.loop)

        if self._async_unsub_polling is not None:
            self._async_unsub_polling()
            self._async_unsub_polling = None

    @callback
    def _update_entity_states(self, now):
        """Update the states of all the polling entities.

        This method must be run in the event loop.
        """
        for entity in self.platform_entities:
            if entity.should_poll:
                self.component.hass.loop.create_task(
                    entity.async_update_ha_state(True)
                )
<commit_msg>Fix blocking/stack trace with empty list (#4191)<commit_after>"""Helpers for components that manage entities."""
import asyncio

from homeassistant import config as conf_util
from homeassistant.bootstrap import (
    async_prepare_setup_platform, async_prepare_setup_component)
from homeassistant.const import (
    ATTR_ENTITY_ID, CONF_SCAN_INTERVAL, CONF_ENTITY_NAMESPACE,
    DEVICE_DEFAULT_NAME)
from homeassistant.core import callback
from homeassistant.exceptions import HomeAssistantError
from homeassistant.loader import get_component
from homeassistant.helpers import config_per_platform, discovery
from homeassistant.helpers.entity import async_generate_entity_id
from homeassistant.helpers.event import async_track_utc_time_change
from homeassistant.helpers.service import extract_entity_ids
from homeassistant.util.async import (
    run_callback_threadsafe, run_coroutine_threadsafe)

DEFAULT_SCAN_INTERVAL = 15

class EntityComponent(object):
    """Helper class that will help a component manage its entities."""

    def __init__(self, logger, domain, hass,
                 scan_interval=DEFAULT_SCAN_INTERVAL, group_name=None):
        """Initialize an entity component."""
        self.logger = logger
        self.hass = hass

        self.domain = domain
        self.entity_id_format = domain + '.{}'
        self.scan_interval = scan_interval
        self.group_name = group_name

        self.entities = {}
        self.group = None

        self.config = None

        self._platforms = {
            'core': EntityPlatform(self, self.scan_interval, None),
        }
        self.async_add_entities = self._platforms['core'].async_add_entities
        self.add_entities = self._platforms['core'].add_entities

    def setup(self, config):
        """Set up a full entity component.

        Loads the platforms from the config and will listen for supported
        discovered platforms.
        """
        run_coroutine_threadsafe(
            self.async_setup(config), self.hass.loop
        ).result()

    @asyncio.coroutine
    def async_setup(self, config):
        """Set up a full entity component.

        Loads the platforms from the config and will listen for supported
        discovered platforms.

        This method must be run in the event loop.
        """
        self.config = config

        # Look in config for Domain, Domain 2, Domain 3 etc and load them
        tasks = []
        for p_type, p_config in config_per_platform(config, self.domain):
            tasks.append(self._async_setup_platform(p_type, p_config))

        yield from asyncio.gather(*tasks, loop=self.hass.loop)

        # Generic discovery listener for loading platform dynamically
        # Refer to: homeassistant.components.discovery.load_platform()
        @callback
        def component_platform_discovered(platform, info):
            """Callback to load a platform."""
            self.hass.loop.create_task(
                self._async_setup_platform(platform, {}, info))

        discovery.async_listen_platform(
            self.hass, self.domain, component_platform_discovered)

    def extract_from_service(self, service, expand_group=True):
        """Extract all known entities from a service call.

        Will return all entities if no entities specified in call.
        Will return an empty list if entities specified but unknown.
        """
        return run_callback_threadsafe(
            self.hass.loop, self.async_extract_from_service, service,
            expand_group
        ).result()

    def async_extract_from_service(self, service, expand_group=True):
        """Extract all known entities from a service call.

        Will return all entities if no entities specified in call.
        Will return an empty list if entities specified but unknown.

        This method must be run in the event loop.
        """
        if ATTR_ENTITY_ID not in service.data:
            return list(self.entities.values())

        return [self.entities[entity_id] for entity_id
                in extract_entity_ids(self.hass, service, expand_group)
                if entity_id in self.entities]

    @asyncio.coroutine
    def _async_setup_platform(self, platform_type, platform_config,
                              discovery_info=None):
        """Setup a platform for this component.

        This method must be run in the event loop.
        """
        platform = yield from async_prepare_setup_platform(
            self.hass, self.config, self.domain, platform_type)

        if platform is None:
            return

        # Config > Platform > Component
        scan_interval = (platform_config.get(CONF_SCAN_INTERVAL) or
                         getattr(platform, 'SCAN_INTERVAL', None) or
                         self.scan_interval)
        entity_namespace = platform_config.get(CONF_ENTITY_NAMESPACE)

        key = (platform_type, scan_interval, entity_namespace)

        if key not in self._platforms:
            self._platforms[key] = EntityPlatform(self, scan_interval,
                                                  entity_namespace)
        entity_platform = self._platforms[key]

        try:
            if getattr(platform, 'async_setup_platform', None):
                yield from platform.async_setup_platform(
                    self.hass, platform_config,
                    entity_platform.async_add_entities, discovery_info
                )
            else:
                yield from self.hass.loop.run_in_executor(
                    None, platform.setup_platform, self.hass, platform_config,
                    entity_platform.add_entities, discovery_info
                )

            self.hass.config.components.append(
                '{}.{}'.format(self.domain, platform_type))
        except Exception:  # pylint: disable=broad-except
            self.logger.exception(
                'Error while setting up platform %s', platform_type)

    def add_entity(self, entity, platform=None, update_before_add=False):
        """Add entity to component."""
        return run_coroutine_threadsafe(
            self.async_add_entity(entity, platform, update_before_add),
            self.hass.loop
        ).result()

    @asyncio.coroutine
    def async_add_entity(self, entity, platform=None, update_before_add=False):
        """Add entity to component.

        This method must be run in the event loop.
        """
        if entity is None or entity in self.entities.values():
            return False

        entity.hass = self.hass

        # update/init entity data
        if update_before_add:
            if hasattr(entity, 'async_update'):
                yield from entity.async_update()
            else:
                yield from self.hass.loop.run_in_executor(None, entity.update)

        if getattr(entity, 'entity_id', None) is None:
            object_id = entity.name or DEVICE_DEFAULT_NAME

            if platform is not None and platform.entity_namespace is not None:
                object_id = '{} {}'.format(platform.entity_namespace,
                                           object_id)

            entity.entity_id = async_generate_entity_id(
                self.entity_id_format, object_id,
                self.entities.keys())

        self.entities[entity.entity_id] = entity
        yield from entity.async_update_ha_state()

        return True

    def update_group(self):
        """Set up and/or update component group."""
        run_callback_threadsafe(
            self.hass.loop, self.async_update_group).result()

    @asyncio.coroutine
    def async_update_group(self):
        """Set up and/or update component group.

        This method must be run in the event loop.
        """
        if self.group is None and self.group_name is not None:
            group = get_component('group')
            self.group = yield from group.Group.async_create_group(
                self.hass, self.group_name, self.entities.keys(),
                user_defined=False
            )
        elif self.group is not None:
            yield from self.group.async_update_tracked_entity_ids(
                self.entities.keys())

    def reset(self):
        """Remove entities and reset the entity component to initial values."""
        run_coroutine_threadsafe(self.async_reset(), self.hass.loop).result()

    @asyncio.coroutine
    def async_reset(self):
        """Remove entities and reset the entity component to initial values.

        This method must be run in the event loop.
        """
        tasks = [platform.async_reset() for platform
                 in self._platforms.values()]

        yield from asyncio.gather(*tasks, loop=self.hass.loop)

        self._platforms = {
            'core': self._platforms['core']
        }
        self.entities = {}
        self.config = None

        if self.group is not None:
            yield from self.group.async_stop()
            self.group = None

    def prepare_reload(self):
        """Prepare reloading this entity component."""
        return run_coroutine_threadsafe(
            self.async_prepare_reload(), loop=self.hass.loop).result()

    @asyncio.coroutine
    def async_prepare_reload(self):
        """Prepare reloading this entity component.

        This method must be run in the event loop.
        """
        try:
            conf = yield from \
                conf_util.async_hass_config_yaml(self.hass)
        except HomeAssistantError as err:
            self.logger.error(err)
            return None

        conf = yield from async_prepare_setup_component(
            self.hass, conf, self.domain)

        if conf is None:
            return None

        yield from self.async_reset()
        return conf

class EntityPlatform(object):
    """Keep track of entities for a single platform and stay in loop."""

    def __init__(self, component, scan_interval, entity_namespace):
        """Initalize the entity platform."""
        self.component = component
        self.scan_interval = scan_interval
        self.entity_namespace = entity_namespace
        self.platform_entities = []
        self._async_unsub_polling = None

    def add_entities(self, new_entities, update_before_add=False):
        """Add entities for a single platform."""
        run_coroutine_threadsafe(
            self.async_add_entities(list(new_entities), update_before_add),
            self.component.hass.loop
        ).result()

    @asyncio.coroutine
    def async_add_entities(self, new_entities, update_before_add=False):
        """Add entities for a single platform async.

        This method must be run in the event loop.
        """
        tasks = [self._async_process_entity(entity, update_before_add)
                 for entity in new_entities]

        # handle empty list from component/platform
        if not tasks:
            return

        yield from asyncio.gather(*tasks, loop=self.component.hass.loop)
        yield from self.component.async_update_group()

        if self._async_unsub_polling is not None or \
           not any(entity.should_poll for entity
                   in self.platform_entities):
            return

        self._async_unsub_polling = async_track_utc_time_change(
            self.component.hass, self._update_entity_states,
            second=range(0, 60, self.scan_interval))

    @asyncio.coroutine
    def _async_process_entity(self, new_entity, update_before_add):
        """Add entities to StateMachine."""
        ret = yield from self.component.async_add_entity(
            new_entity, self, update_before_add=update_before_add
        )
        if ret:
            self.platform_entities.append(new_entity)

    @asyncio.coroutine
    def async_reset(self):
        """Remove all entities and reset data.

        This method must be run in the event loop.
        """
        tasks = [entity.async_remove() for entity in self.platform_entities]

        yield from asyncio.gather(*tasks, loop=self.component.hass.loop)

        if self._async_unsub_polling is not None:
            self._async_unsub_polling()
            self._async_unsub_polling = None

    @callback
    def _update_entity_states(self, now):
        """Update the states of all the polling entities.

        This method must be run in the event loop.
        """
        for entity in self.platform_entities:
            if entity.should_poll:
                self.component.hass.loop.create_task(
                    entity.async_update_ha_state(True)
                )
<|endoftext|>


<commit_before># digitalRead.py - Alexander Hiam - 2/2012
# USR3 LED mirrors GPIO1_6 until CTRL-C is pressed.

# Import PyBBIO library:
from bbio import *

# Create a setup function:
def setup():
  # Set the GPIO pins:
  pinMode('USR3', OUTPUT)
  pinMode('GPIO1_6', INPUT)

# Create a main function:
def main():
  state = digitalRead('GPIO1_6')
  digitalWrite('USR3', state)
  # It's good to put a bit of a delay in if possible
  # to keep the processor happy:
  sleep(0.1)

# Start the loop:
run(setup, main)
<commit_msg>updated to use pin constants instead of strings<commit_after># digitalRead.py - Alexander Hiam - 2/2012
# USR3 LED mirrors GPIO1_6 until CTRL-C is pressed.

# Import PyBBIO library:
from bbio import *

# Create a setup function:
def setup():
  # Set the GPIO pins:
  pinMode(USR3, OUTPUT)
  pinMode(GPIO1_6, INPUT)

# Create a main function:
def main():
  state = digitalRead(GPIO1_6)
  digitalWrite(USR3, state)
  # It's good to put a bit of a delay in if possible
  # to keep the processor happy:
  sleep(0.1)

# Start the loop:
run(setup, main)
<|endoftext|>


<commit_before>#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
#   Copyright 2019 Romain Boman
#
#   Licensed under the Apache License, Version 2.0 (the "License");
#   you may not use this file except in compliance with the License.
#   You may obtain a copy of the License at
#
#       http://www.apache.org/licenses/LICENSE-2.0
#
#   Unless required by applicable law or agreed to in writing, software
#   distributed under the License is distributed on an "AS IS" BASIS,
#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#   See the License for the specific language governing permissions and
#   limitations under the License.

import sys
import os
import subprocess
import re

from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *

from ui_widget import Ui_Form

# ffmpeg -y -r 10 -i anim%4d.png -vf fps=25 -c:v libx264 -crf 18 -pix_fmt yuv420p video.mp4

class Window(QWidget, Ui_Form):
    def __init__(self, parent=None):
        super(Window, self).__init__(parent)
        self.setupUi(self)

        self.input_fps_lineEdit.setValidator(QIntValidator(0, 1000))
        self.output_fps_lineEdit.setValidator(QIntValidator(0, 1000))

        self.quality_Slider.setTickPosition(QSlider.TicksBothSides)
        self.quality_Slider.setTickInterval(1)
        self.quality_Slider.valueChanged.connect(
            lambda i: QToolTip.showText(QCursor.pos(), "%d" % i))

        # stdio redirection
        self.stdout, sys.stdout = sys.stdout, self
        # self.stderr, sys.stderr = sys.stderr, self
        self.buf = ''

        # images
        self.pix = []

        # read settings
        settings = QSettings()
        self.restoreGeometry(settings.value("Geometry", self.saveGeometry()))
        self.ffmpegfolder_lineEdit.setText(settings.value("ffmpegfolder", ""))
        self.workspace_lineEdit.setText(settings.value("workspace", ""))
        self.filenames_lineEdit.setText(
            settings.value("filenames", "anim%4d.png"))
        self.outdir_lineEdit.setText(settings.value("outdir", ""))
        self.outname_lineEdit.setText(
            settings.value("outname", "video.mp4"))
        self.input_fps_lineEdit.setText(settings.value("input_fps", "10"))
        self.output_fps_lineEdit.setText(settings.value("output_fps", "25"))
        self.quality_Slider.setValue(int(settings.value("quality", 19)))

        iconfile = os.path.join(os.path.dirname(
            __file__), '..', '..', 'ico', 'boomy-forward.png')
        self.setWindowIcon(QIcon(iconfile))

    def on_play_Button_pressed(self):
        print("running ffplay...")
        self.runPRG("ffplay")

    def on_probe_Button_pressed(self):
        print("running ffprobe...")
        self.runPRG("ffprobe")

    def runPRG(self, pname):
        exeffplay = self.getExe(pname)
        if not exeffplay:
            QMessageBox.critical(
                self, 'Error', '%s does not exist/work!\nCheck ffmpeg path.' % pname)
            return
        cmd = []
        cmd.append(exeffplay)
        outfile = os.path.join(self.outdir_lineEdit.text(),
                               self.outname_lineEdit.text())
        if not os.path.isfile(outfile):
            QMessageBox.critical(
                self, 'Error', 'The video has not been generated yet!\n%s does not exist' % outfile)
            return
        cmd.append(outfile)
        print('\t', cmd)
        try:
            retcode = subprocess.call(cmd)
            print("\tretcode =", retcode)
        except Exception as e:
            print(e)

    def on_check_Button_pressed(self):

        print("folders:")
        for p, f in [('ffmpeg', self.ffmpegfolder_lineEdit.text()),
                     ('workspace', self.workspace_lineEdit.text()),
                     ('output', self.outdir_lineEdit.text())]:
            print("\t.", p, end=' ')
            if not f:
                print("empty")
            if os.path.isdir(f):
                print("exists!")
            else:
                print("doesn't exist!")

        print("programs:")
        for p in ['ffmpeg', 'ffplay', 'ffprobe']:
            print("\t.", p, end=' ')
            exe = self.getExe(p)
            where = 'from PATH' if exe == p else 'from ffmpeg folder'
            if exe:
                print("found: %s (%s)" % (exe, where))
            else:
                print("NOT FOUND!")

        if os.path.isdir(self.workspace_lineEdit.text()):
            print("images:")
            # convert sscanf format to regex: anim%4d.png => anim(\d{4}).png
            regex = re.sub(
                '(\\%(\\d)d)', '(\\\d{\\2})', self.filenames_lineEdit.text())
            print("\t. pattern converted to regex:", regex)
            pattern = re.compile(regex)

            nofiles = 0
            lowno = 0
            highno = 0
            self.pix = []
            self.pixnames = []
            for f in sorted(os.listdir(self.workspace_lineEdit.text())):
                match = pattern.match(f)
                if(match):
                    nofiles += 1
                    g = match.groups()
                    no = int(g[0])
                    highno = max(no, highno)
                    lowno = min(no, lowno)
                    self.pixnames.append(os.path.join(
                        self.workspace_lineEdit.text(), f))
            print("\t. %d files found ranging from %d to %d" % (
                nofiles, lowno, highno))

            if len(self.pixnames):
                progress = QProgressDialog(
                    "image", "Cancel", 0, len(self.pixnames), self)
                progress.setWindowModality(Qt.WindowModal)
                progress.setWindowTitle("Building preview...")
                progress.setValue(0)
                progress.forceShow()

                for i, f in enumerate(self.pixnames):
                    progress.setValue(i+1)
                    progress.setLabelText(f)
                    if progress.wasCanceled():
                        self.pix = []
                        self.pixname = []
                        lowno = 0
                        highno = 100
                        break
                    img = QPixmap(f)  # loads original image
                    # reduce img size if too large
                    w = min(img.width(), 500)
                    img_scaled = img.scaledToWidth(w, Qt.SmoothTransformation)
                    self.pix.append(img_scaled)

            if len(self.pix):
                self.img_Label.setPixmap(self.pix[0])
            else:
                self.img_Label.setText("No preview")

            self.img_Slider.setMinimum(lowno)
            self.img_Slider.setMaximum(highno)

    def on_img_Slider_valueChanged(self):
        no = self.img_Slider.value()
        QToolTip.showText(QCursor.pos(), "%d" % no)
        #print "slider =",no

        if len(self.pix) > no:
            self.img_Label.setPixmap(self.pix[no])

    def checkExe(self, exe):
        try:
            # try to call it (with a dummy arg - faster than -h)
            with open(os.devnull, 'w') as FNULL:
                subprocess.call([exe, '-prout'], stdout=FNULL,
                                stderr=subprocess.STDOUT)
            return exe
        except OSError:
            return ""

    def getExe(self, exename):

        # try the provided folder name
        if self.ffmpegfolder_lineEdit.text():
            exeinfolder = os.path.join(
                self.ffmpegfolder_lineEdit.text(), exename)
            exe = self.checkExe(exeinfolder)
            if exe:
                return exe
        # try ffmpeg in the PATH
        return self.checkExe(exename)

    def on_convert_Button_pressed(self):

        exeffmpeg = self.getExe("ffmpeg")
        if not exeffmpeg:
            QMessageBox.critical(
                self, 'Error', 'ffmpeg does not exist/work!\nCheck ffmpeg path.')

        cmd = []
        cmd.append(exeffmpeg)
        cmd.append('-y')
        # cmd +="-r %s " %
        cmd.extend(['-r', self.input_fps_lineEdit.text()])

        # check workspace folder
        wrkdir = self.workspace_lineEdit.text()
        if not os.path.isdir(wrkdir):
            QMessageBox.critical(
                self, 'Error', 'The workspace folder does not exist!')
            return

        inpfiles = os.path.join(
            self.workspace_lineEdit.text(), self.filenames_lineEdit.text())
        #cmd +="-i %s " % inpfiles
        cmd.extend(['-i', inpfiles])
        #cmd +="-vf fps=%s " % self.output_fps_lineEdit.text()
        cmd.extend(['-vf', 'fps=%s' % self.output_fps_lineEdit.text()])
        #cmd +="-c:v libx264 "
        cmd.extend(['-c:v', 'libx264'])
        #cmd +="-crf %d " % self.quality_Slider.value()
        cmd.extend(['-crf', '%d' % self.quality_Slider.value()])
        #cmd +="-pix_fmt yuv420p "
        cmd.extend(['-pix_fmt', 'yuv420p'])
        # cmd +="-vf \"scale=trunc(iw/2)*2:trunc(ih/2)*2\" " # scale if not multiple of 2
        #cmd +="-vf \"scale=trunc(iw/2)*2:trunc(ih/2)*2, setsar=1\" "
        # cmd +="-vf \"crop=trunc(iw/2)*2:trunc(ih/2)*2:0:0\" " # crop to odd dimensions...
        cmd.extend(['-vf', 'crop=trunc(iw/2)*2:trunc(ih/2)*2:0:0'])

        # check output folder
        outdir = self.outdir_lineEdit.text()
        if not os.path.isdir(outdir):
            QMessageBox.critical(
                self, 'Error', 'The output folder does not exist!')
            return

        # check / correct output filename
        outname = self.outname_lineEdit.text()
        if outname == '':
            outname = 'video.mp4'
        base, ext = os.path.splitext(outname)
        if(ext != '.mp4'):
            outname = outname+'.mp4'
        self.outname_lineEdit.setText(outname)

        # check whether output file will be overwritten
        outfile = os.path.join(self.outdir_lineEdit.text(),
                               self.outname_lineEdit.text())
        if os.path.isfile(outfile):
            reply = QMessageBox.question(self, 'Message',
                                         "The output file already exists. Do you want to overwrite it?",
                                         QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
            if reply == QMessageBox.No:
                print("output file exists - operation cancelled.")
                return

        cmd.append(outfile)
        print("running ffmpeg...")
        print('\t', cmd)

        # sous linux, cmd doit etre une liste a moins que shell=True (pas safe)
        # dans ce cas, python se charge d'ajouter des guillemets là ou il faut.
        # sous windows, ca marche sans shell=True avec une bete string.
        # => on utilise une liste
        retcode = subprocess.call(cmd)

        print("\tretcode =", retcode)

    def on_ffmpegfolder_Button_pressed(self):
        dir = QFileDialog.getExistingDirectory(
            self, "Find ffmpeg folder", self.ffmpegfolder_lineEdit.text())
        if dir:
            self.ffmpegfolder_lineEdit.setText(QDir.toNativeSeparators(dir))

    def on_workspace_Button_pressed(self):
        dir = QFileDialog.getExistingDirectory(
            self, "Find workspace folder", self.workspace_lineEdit.text())
        if dir:
            self.workspace_lineEdit.setText(QDir.toNativeSeparators(dir))

    def on_outdir_Button_pressed(self):
        dir = QFileDialog.getExistingDirectory(
            self, "Choose output folder", self.outdir_lineEdit.text())
        if dir:
            self.outdir_lineEdit.setText(QDir.toNativeSeparators(dir))

    def closeEvent(self, event):
        # save settings to registry
        settings = QSettings()
        settings.setValue("Geometry", QVariant(self.saveGeometry()))
        settings.setValue("ffmpegfolder", QVariant(
            self.ffmpegfolder_lineEdit.text()))
        settings.setValue("workspace", QVariant(
            self.workspace_lineEdit.text()))
        settings.setValue("filenames", QVariant(
            self.filenames_lineEdit.text()))
        settings.setValue("outdir", QVariant(
            self.outdir_lineEdit.text()))
        settings.setValue("outname", QVariant(
            self.outname_lineEdit.text()))
        settings.setValue("input_fps", QVariant(
            self.input_fps_lineEdit.text()))
        settings.setValue("output_fps", QVariant(
            self.output_fps_lineEdit.text()))
        settings.setValue("quality", QVariant(self.quality_Slider.value()))
        event.accept()

    def write(self, stuff):
        "stdio redirection"
        if '\n' in stuff:
            list(map(self.writeLine, stuff.split("\n")))
        else:
            self.buf += stuff
        qApp.processEvents()

    def flush(self): # required by py3 stdout redirection
        pass

    def writeLine(self, stuff):
        "stdio redirection"
        if len(self.buf):
            stuff = self.buf + stuff
            self.buf = ''
            self.textEdit.append(stuff)
        else:
            if stuff != '':
                self.textEdit.append(stuff)

def main():
    app = QApplication(sys.argv)
    app.setOrganizationName("RoBo")
    app.setApplicationName("ffmpeg_GUI")
    win = Window()
    win.setWindowTitle('%s' % os.path.basename(sys.argv[0]))
    win.show()
    app.lastWindowClosed.connect(app.quit)
    sys.exit(app.exec_())

if __name__ == "__main__":
    main()
<commit_msg>conversion based on a list of files<commit_after>#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
#   Copyright 2019-2021 Romain Boman
#
#   Licensed under the Apache License, Version 2.0 (the "License");
#   you may not use this file except in compliance with the License.
#   You may obtain a copy of the License at
#
#       http://www.apache.org/licenses/LICENSE-2.0
#
#   Unless required by applicable law or agreed to in writing, software
#   distributed under the License is distributed on an "AS IS" BASIS,
#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#   See the License for the specific language governing permissions and
#   limitations under the License.

"""A simple Qt GUI for creating movies for a series of bitmap screenshots.

This is a wrapper around ffmpeg and related tools.
(https://ffmpeg.org/)

The program displays the set of images before running ffmpeg.

Run the script, set the options in the GUI, click "check" (mandatory), then "convert".

TODO: should be (re)tested on linux
"""

import sys
import os
import subprocess
import re
import fnmatch

from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *

from ui_widget import Ui_Form

# note: "old" ffmpeg cmd line usage
#   ffmpeg -y -r 10 -i anim%4d.png -vf fps=25 -c:v libx264 -crf 18 -pix_fmt yuv420p video.mp4
# (the script now uses a text file as imput so that more complex filename patterns can be used.)

class Window(QWidget, Ui_Form):

    tmpfile = "files.ffmpeg.tmp"

    def __init__(self, parent=None):
        super(Window, self).__init__(parent)
        self.setupUi(self)

        self.input_fps_lineEdit.setValidator(QIntValidator(0, 1000))
        self.output_fps_lineEdit.setValidator(QIntValidator(0, 1000))

        self.quality_Slider.setTickPosition(QSlider.TicksBothSides)
        self.quality_Slider.setTickInterval(1)
        self.quality_Slider.valueChanged.connect(
            lambda i: QToolTip.showText(QCursor.pos(), "%d" % i))

        # stdio redirection
        self.stdout, sys.stdout = sys.stdout, self
        # self.stderr, sys.stderr = sys.stderr, self
        self.buf = ''

        # images
        self.pix = []

        # read Qt settings for the application
        settings = QSettings()
        self.restoreGeometry(settings.value("Geometry", self.saveGeometry()))
        self.ffmpegfolder_lineEdit.setText(settings.value("ffmpegfolder", ""))
        self.workspace_lineEdit.setText(settings.value("workspace", ""))
        self.filenames_lineEdit.setText(
            settings.value("filenames", "anim*.png"))
        self.outdir_lineEdit.setText(settings.value("outdir", ""))
        self.outname_lineEdit.setText(
            settings.value("outname", "video.mp4"))
        self.input_fps_lineEdit.setText(settings.value("input_fps", "10"))
        self.output_fps_lineEdit.setText(settings.value("output_fps", "25"))
        self.quality_Slider.setValue(int(settings.value("quality", 19)))

        iconfile = os.path.join(os.path.dirname(
            __file__), '..', '..', 'ico', 'boomy-forward.png')
        self.setWindowIcon(QIcon(iconfile))

    def on_play_Button_pressed(self):
        print("running ffplay...")
        self.runPRG("ffplay")

    def on_probe_Button_pressed(self):
        print("running ffprobe...")
        self.runPRG("ffprobe")

    def runPRG(self, pname):
        exeffplay = self.getExe(pname)
        if not exeffplay:
            QMessageBox.critical(
                self, 'Error', '%s does not exist/work!\nCheck ffmpeg path.' % pname)
            return
        cmd = []
        cmd.append(exeffplay)
        outfile = os.path.join(self.outdir_lineEdit.text(),
                               self.outname_lineEdit.text())
        if not os.path.isfile(outfile):
            QMessageBox.critical(
                self, 'Error', 'The video has not been generated yet!\n%s does not exist' % outfile)
            return
        cmd.append(outfile)
        print('\t', cmd)
        try:
            retcode = subprocess.call(cmd)
            print("\tretcode =", retcode)
        except Exception as e:
            print(e)

    def on_check_Button_pressed(self):

        # check folders
        print("folders:")
        for p, f in [('ffmpeg', self.ffmpegfolder_lineEdit.text()),
                     ('workspace', self.workspace_lineEdit.text()),
                     ('output', self.outdir_lineEdit.text())]:
            print("\t.", p, end=' ')
            if not f:
                print("empty")
            if os.path.isdir(f):
                print("exists!")
            else:
                print("doesn't exist!")

        # check programs
        print("programs:")
        for p in ['ffmpeg', 'ffplay', 'ffprobe']:
            print("\t.", p, end=' ')
            exe = self.getExe(p)
            where = 'from PATH' if exe == p else 'from ffmpeg folder'
            if exe:
                print("found: %s (%s)" % (exe, where))
            else:
                print("NOT FOUND!")

        if os.path.isdir(self.workspace_lineEdit.text()):
            print("images:")
            # convert sscanf format to regex: anim%4d.png => anim(\d{4}).png
            # regex = re.sub(
            #     '(\\%(\\d)d)', '(\\\d{\\2})', self.filenames_lineEdit.text())
            # print("\t. pattern converted to regex:", regex)
            # pattern = re.compile(regex)
            pattern = self.filenames_lineEdit.text()

            nofiles = 0
            # lowno = 0
            # highno = 0
            self.pix = []
            self.pixnames = []
            for f in sorted(os.listdir(self.workspace_lineEdit.text())):
                # match = pattern.match(f)
                if fnmatch.fnmatch(f, pattern):
                # if(match):
                    nofiles += 1
                    # g = match.groups()
                    # no = int(g[0])
                    # highno = max(no, highno)
                    # lowno = min(no, lowno)
                    self.pixnames.append(os.path.join(
                        self.workspace_lineEdit.text(), f))
            # print("\t. %d files found ranging from %d to %d" % (
            #     nofiles, lowno, highno))
            print("\t. %d files found" % ( nofiles))

            # sort pixnames in a "natural" way (fig10.png after fig1.png)
            self.pixnames.sort(key=lambda f: int(re.sub('\D', '', f)))

            # create a file with filenames (TODO: could be done in "convert")
            #   this allows us to have missing files (some holes in the numbering)
            #   or numbers not filled with zeros: e.g. 1 instead of 0001
            #   which are required by the "-i %4d" command argument.
            listfile = os.path.join(self.workspace_lineEdit.text(), self.tmpfile)
            f=open(listfile, "w")
            for p in self.pixnames:
                # f.write(f"file './{os.path.basename(p)}'\n")
                f.write(f"file '{p}'\n")
                # f.write(f'duration {1/int(self.input_fps_lineEdit.text())}\n')
                f.write(f'duration 1\n')
                # "duration": aucune influence sur le résultat vu qu'on redéfinit "-r input_fps"
                # par contre si on supprime cette ligne, des warnings s'affichent (mais
                # la video est OK)
            f.close()
            print(f'{listfile} created.')

            if len(self.pixnames):
                progress = QProgressDialog(
                    "image", "Cancel", 0, len(self.pixnames), self)
                progress.setWindowModality(Qt.WindowModal)
                progress.setWindowTitle("Building preview...")
                progress.setValue(0)
                progress.forceShow()

                for i, f in enumerate(self.pixnames):
                    progress.setValue(i+1)
                    progress.setLabelText(f)
                    if progress.wasCanceled():
                        self.pix = []
                        self.pixname = []
                        # lowno = 0
                        # highno = 100
                        break
                    img = QPixmap(f)  # loads original image
                    # reduce img size if too large
                    w = min(img.width(), 500)
                    img_scaled = img.scaledToWidth(w, Qt.SmoothTransformation)
                    self.pix.append(img_scaled)

            if len(self.pix):
                self.img_Label.setPixmap(self.pix[0])
            else:
                self.img_Label.setText("No preview")

            # self.img_Slider.setMinimum(lowno)
            # self.img_Slider.setMaximum(highno)
            self.img_Slider.setMinimum(0.0)
            self.img_Slider.setMaximum(nofiles)

    def on_img_Slider_valueChanged(self):
        no = self.img_Slider.value()
        QToolTip.showText(QCursor.pos(), "%d" % no)
        #print "slider =",no

        if len(self.pix) > no:
            self.img_Label.setPixmap(self.pix[no])

    def checkExe(self, exe):
        try:
            # try to call it (with a dummy arg - faster than -h)
            with open(os.devnull, 'w') as FNULL:
                subprocess.call([exe, '-prout'], stdout=FNULL,
                                stderr=subprocess.STDOUT)
            return exe
        except OSError:
            return ""

    def getExe(self, exename):
        """look for ffmpeg
        """
        # try the provided folder name
        if self.ffmpegfolder_lineEdit.text():
            exeinfolder = os.path.join(
                self.ffmpegfolder_lineEdit.text(), exename)
            exe = self.checkExe(exeinfolder)
            if exe:
                return exe
        # try ffmpeg in the PATH
        return self.checkExe(exename)

    def on_convert_Button_pressed(self):
        """`Convert` Button
        """
        exeffmpeg = self.getExe("ffmpeg")
        if not exeffmpeg:
            QMessageBox.critical(
                self, 'Error', 'ffmpeg does not exist/work!\nCheck ffmpeg path.')

        cmd = []
        cmd.append(exeffmpeg)

        cmd.extend(['-f', 'concat'])    # concat filter is more versatile that "-i pattern%4d.png"
        cmd.extend(['-safe', '0'])      # allows absolute paths in the input text file

        cmd.extend(['-r', self.input_fps_lineEdit.text()]) # input FPS (override the one written in the text file)
        cmd.extend(['-i', os.path.join(self.workspace_lineEdit.text(), self.tmpfile)]) # input file (written in "check")

        cmd.append('-y') # overwrite output

        # check workspace folder
        wrkdir = self.workspace_lineEdit.text()
        if not os.path.isdir(wrkdir):
            QMessageBox.critical(
                self, 'Error', 'The workspace folder does not exist!')
            return

        cmd.extend(['-c:v', 'libx264'])   # codec
        cmd.extend(['-crf', '%d' % self.quality_Slider.value()]) # quality
        cmd.extend(['-pix_fmt', 'yuv420p']) # compatibility
        # add 2 filters
        #   - first one = "crop": crop to even dimensions required by the mp4 codec
        #   - second one = "fps": control the output fps
        cmd.extend(['-filter:v', f'crop=trunc(iw/2)*2:trunc(ih/2)*2:0:0,fps={self.output_fps_lineEdit.text()}'])

        # check output folder
        outdir = self.outdir_lineEdit.text()
        if not os.path.isdir(outdir):
            QMessageBox.critical(
                self, 'Error', 'The output folder does not exist!')
            return

        # check / correct output filename
        outname = self.outname_lineEdit.text()
        if outname == '':
            outname = 'video.mp4'
        base, ext = os.path.splitext(outname)
        if(ext != '.mp4'):
            outname = outname+'.mp4'
        self.outname_lineEdit.setText(outname)

        # check whether output file will be overwritten
        outfile = os.path.join(self.outdir_lineEdit.text(),
                               self.outname_lineEdit.text())
        if os.path.isfile(outfile):
            reply = QMessageBox.question(self, 'Message',
                                         "The output file already exists. Do you want to overwrite it?",
                                         QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
            if reply == QMessageBox.No:
                print("output file exists - operation cancelled.")
                return

        cmd.append(outfile)
        print("running ffmpeg...")
        print('\t', cmd)

        # sous linux, cmd doit etre une liste a moins que shell=True (pas safe)
        # dans ce cas, python se charge d'ajouter des guillemets là ou il faut.
        # sous windows, ca marche sans shell=True avec une bete string.
        # => on utilise une liste
        retcode = subprocess.call(cmd)

        print("\tretcode =", retcode)

    def on_ffmpegfolder_Button_pressed(self):
        dir = QFileDialog.getExistingDirectory(
            self, "Find ffmpeg folder", self.ffmpegfolder_lineEdit.text())
        if dir:
            self.ffmpegfolder_lineEdit.setText(QDir.toNativeSeparators(dir))

    def on_workspace_Button_pressed(self):
        dir = QFileDialog.getExistingDirectory(
            self, "Find workspace folder", self.workspace_lineEdit.text())
        if dir:
            self.workspace_lineEdit.setText(QDir.toNativeSeparators(dir))

    def on_outdir_Button_pressed(self):
        dir = QFileDialog.getExistingDirectory(
            self, "Choose output folder", self.outdir_lineEdit.text())
        if dir:
            self.outdir_lineEdit.setText(QDir.toNativeSeparators(dir))

    def closeEvent(self, event):
        """save settings to registry and quit
        """
        settings = QSettings()
        settings.setValue("Geometry", QVariant(self.saveGeometry()))
        settings.setValue("ffmpegfolder", QVariant(
            self.ffmpegfolder_lineEdit.text()))
        settings.setValue("workspace", QVariant(
            self.workspace_lineEdit.text()))
        settings.setValue("filenames", QVariant(
            self.filenames_lineEdit.text()))
        settings.setValue("outdir", QVariant(
            self.outdir_lineEdit.text()))
        settings.setValue("outname", QVariant(
            self.outname_lineEdit.text()))
        settings.setValue("input_fps", QVariant(
            self.input_fps_lineEdit.text()))
        settings.setValue("output_fps", QVariant(
            self.output_fps_lineEdit.text()))
        settings.setValue("quality", QVariant(self.quality_Slider.value()))
        event.accept()

    def write(self, stuff):
        """std IO redirection
        """
        if '\n' in stuff:
            list(map(self.writeLine, stuff.split("\n")))
        else:
            self.buf += stuff
        qApp.processEvents()

    def flush(self): # required by py3 stdout redirection
        """std IO redirection
        """
        pass

    def writeLine(self, stuff):
        """std IO redirection
        """
        if len(self.buf):
            stuff = self.buf + stuff
            self.buf = ''
            self.textEdit.append(stuff)
        else:
            if stuff != '':
                self.textEdit.append(stuff)

def main():
    app = QApplication(sys.argv)
    app.setOrganizationName("RoBo")
    app.setApplicationName("ffmpeg_GUI")
    win = Window()
    win.setWindowTitle('%s' % os.path.basename(sys.argv[0]))
    win.show()
    app.lastWindowClosed.connect(app.quit)
    sys.exit(app.exec_())

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


<commit_before># -*- coding: utf-8 -*-
##############################################################################
#
#    Author:  Alexandre Fayolle
#    Copyright 2012 Camptocamp SA
#
#    This program is free software: you can redistribute it and/or modify
#    it under the terms of the GNU Affero General Public License as
#    published by the Free Software Foundation, either version 3 of the
#    License, or (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU Affero General Public License for more details.
#
#    You should have received a copy of the GNU Affero General Public License
#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
{'name' : 'Product Historical Margin',
 'version' : '0.1',
 'author' : 'Camptocamp',
 'maintainer': 'Camptocamp',
 'category': 'Accounting & Finance',
 'complexity': "normal",  # easy, normal, expert
 'depends' : ['product_get_cost_field',
              'account',
              ],
 'description': """Provides an improved way of computing the margin and markup of a product, especially for product with a averaged cost price. XXX
 """,
 'website': 'http://www.camptocamp.com/',
 'init_xml': [],
 'update_xml': [],
 'demo_xml': [],
 'tests': [],
 'installable': True,
 'auto_install': False,
 'license': 'AGPL-3',
 'application': False
 }
<commit_msg>[FIX] product_historical_margin: added XML files in manifest (lp:c2c-addons/6.1  rev 40.1.28)<commit_after># -*- coding: utf-8 -*-
##############################################################################
#
#    Author:  Alexandre Fayolle
#    Copyright 2012 Camptocamp SA
#
#    This program is free software: you can redistribute it and/or modify
#    it under the terms of the GNU Affero General Public License as
#    published by the Free Software Foundation, either version 3 of the
#    License, or (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU Affero General Public License for more details.
#
#    You should have received a copy of the GNU Affero General Public License
#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
{'name' : 'Product Historical Margin',
 'version' : '0.1',
 'author' : 'Camptocamp',
 'maintainer': 'Camptocamp',
 'category': 'Accounting & Finance',
 'complexity': "normal",  # easy, normal, expert
 'depends' : ['product_get_cost_field',
              'account',
              ],
 'description': """Provides an improved way of computing the margin and markup of a product, especially for product with a averaged cost price. XXX
 """,
 'website': 'http://www.camptocamp.com/',
 'init_xml': [],
 'update_xml': ["account_invoice_view.xml"],
 'demo_xml': [],
 'tests': [],
 'installable': True,
 'auto_install': False,
 'license': 'AGPL-3',
 'application': False
 }
<|endoftext|>


<commit_before>""" The various classes relating to animations """
from __future__ import print_function
from __future__ import division

import math

from random import randint
import time

class Animation(object):
    """The base class for any animation. An animation is a state machine that produces frames.
       Keep calling get_frame until is_complete returns true.
    """
    def __init__(self, milliseconds=None):
        """ Animation base class initializer """
        object.__init__(self)
        if milliseconds is None:
            self._milliseconds = lambda: int(round(time.time() * 1000))
        else:
            self._milliseconds = milliseconds

    def get_frame(self):
        """Return an array of tuples (r,g,b) i.e. the frame for the current state of the animation"""
        raise RuntimeError("GetFrame should only be called in derived classes")

    def is_complete(self):
        """True if this animation is complete and can be removed"""
        return False

class FireAnimation(Animation):
    """ Fire animation """
    def __init__(self):
        Animation.__init__(self)
        self._lights = []
        self._r = 255
        self._g = 255 - 40
        self._b = 40
        self._end = 0

    def get_frame(self):
        if self._milliseconds() > self._end:
            self._end = self._milliseconds() + 50
            self._lights = []
            for i in range(0, 88):
                flicker = randint(0, 150)
                r1 = self._r - flicker
                g1 = self._g - flicker
                b1 = self._b - flicker
                if r1 < 0:
                    r1 = 0
                if g1 < 0:
                    g1 = 0
                if b1 < 0:
                    b1 = 0
                self._lights.append((r1, g1, b1))
        return self._lights

    def is_complete(self):
        return False

class BeatAnimation(Animation):
    """Lights up on a specific beat"""
    def __init__(self, width, bpm, milliseconds=None):
        Animation.__init__(self, milliseconds=None)
        self._ms_per_beat = 1000 / (bpm / 60)
        self._current_pulse_time = self._milliseconds()
        self._width = width
        self._bell_curve = BeatAnimation.create_bell_curve(width)

    @classmethod
    def create_bell_curve(cls, width):
        """ Create a bell curve with width elements and values between 0 and 1.
            The standard deviation value of 0.4 means the curve will peak at 1.
            Starting at around -1.5 to 1.5 gives a nice ramp up and down."""

        # Need to step between -1.5 and 1.5
        step = 2.0 / width
        x = -1
        curve = []

        for _ in range(width):
            curve.append(cls.normpdf(x, 0, 0.4))
            x += step
        return curve

    def get_frame(self):
        now = self._milliseconds()
        time_into_beat = now % self._ms_per_beat

        # Brightness decreases as time progresses into the beat. Adjust to an interval between 0-255.
        brightness = int((self._ms_per_beat - time_into_beat) / self._ms_per_beat * 256)
        pixels = [(brightness, brightness, brightness)] * self._width

        # Apply a bell curve to pixels - this avoids all of them lighting up and instead a soft ramp up and ramp down
        for i, (r, g, b) in enumerate(pixels):
            factor = self._bell_curve[i]
            pixels[i] = (int(r * factor), int(g * factor), int(b * factor))
        return pixels

    def is_complete(self):
        return False

    @classmethod
    def normpdf(cls, x, mean, standard_deviation):
        """ Calculates the normal distribution using a probability density function
            Found it here https://stackoverflow.com/a/12413491 """
        var = float(standard_deviation)**2
        pi = 3.1415926
        denom = (2*pi*var)**.5
        num = math.exp(-(float(x)-float(mean))**2/(2*var))
        return num/denom

class LightUpAnimation(Animation):
    """Simple animation that lights up the given key for a short period of time"""

    def __init__(self, keys, key_pressed, duration=1000, milliseconds=None):
        """Initializes a new LightUpAnimation instance"""
        Animation.__init__(self)
        self._end = self._milliseconds() + duration
        self._leds = [(0, 0, 0)] * keys
        self._key_pressed = key_pressed

    def get_frame(self):
        """Return an array of integers representing the current state of the animation"""
        self._leds[self._key_pressed] = (255, 255, 255)
        return self._leds

    def is_complete(self):
        """True if this animation is complete and can be removed"""
        return self._milliseconds() > self._end

class PressureKeyPressAnimation(LightUpAnimation):
    """Simple animation that happens when you press a key. It is pressure sensitive."""

    def __init__(self, keys, key_pressed, velocity, duration=1000, milliseconds=None):
        """Initializes a new PressureKeyPressAnimation instance"""
        LightUpAnimation.__init__(self, keys, key_pressed, duration, milliseconds)
        self._velocity = velocity
        self._duration = duration

    def get_key_color(self):
        """Returns the color of the key pressed during animation. Override to change."""
        return (self._velocity, self._velocity, self._velocity)

    def get_frame(self):
        """Return an array of integers representing the current state of the animation."""

        time_left = self._end - self._milliseconds()
        if time_left < 0:
            time_left = 0

        r, g, b = self.get_key_color()
        fade_factor = time_left / self._duration
        r = int(r * fade_factor)
        g = int(g * fade_factor)
        b = int(b * fade_factor)

        self._leds[self._key_pressed] = (r, g, b)
        return self._leds

class RunLeftAnimation(Animation):
    """Simple animation that happens when you press a key"""

    def __init__(self, key_pressed):
        """Initializes a new KeyPressAnimation instance"""
        Animation.__init__(self)
        self._key_pressed = key_pressed
        r = randint(0, 3)
        if r == 0:
            self._color = (255, 0, 0)
        if r == 1:
            self._color = (255, 255, 255)
        if r == 2:
            self._color = (255, 255, 0)
        if r == 3:
            self._color = (0, 255, 255)

    def get_frame(self):
        """Return an array of integers representing the current state of the animation"""
        leds = [(0, 0, 0)] * 88
        leds[self._key_pressed] = self._color
        self._key_pressed -= 1
        return leds

    def is_complete(self):
        """True if this animation is complete and can be removed"""
        return self._key_pressed < 0

class ChristmasKeyPressAnimation(PressureKeyPressAnimation):
    """Simple animation that happens when you press a key. It is pressure sensitive."""

    def __init__(self, keys, key_pressed, velocity, duration=1000):
        """Initializes a new ChristmasKeyPressAnimation instance"""
        PressureKeyPressAnimation.__init__(self, keys, key_pressed, velocity, duration)
        color = randint(0, 2)

        if color == 0:
            self._color = (velocity, 0, 0)
        if color == 1:
            self._color = (0, velocity, 0)
        if color == 2:
            self._color = (velocity, velocity, velocity)

    def get_key_color(self):
        """Overrides the default and return a Christmasey color"""
        return self._color

class RunningAnimation(Animation):
    """Animation the moves each time a key is pressed"""
    def __init__(self, keys, milliseconds=None):
        Animation.__init__(self, milliseconds)
        # This will hold the active key animations
        self._animations = []
        self._keys = keys
        self._key = 0

    def key_pressed(self, velocity):
        """Call whenever a key is pressed"""
        self._animations.append(PressureKeyPressAnimation(self._keys, self._key, velocity, 1000, self._milliseconds))
        self._key = self._key + 1
        self._key = self._key % self._keys

    def get_frame(self):
        leds = [(0, 0, 0)] * self._keys
        for current_animation in self._animations:
            new_frame = current_animation.get_frame()
            for i, frame_pixel in enumerate(new_frame):
                r, g, b = (frame_pixel)
                if r > 0 or g > 0 or b > 0:
                    leds[i] = frame_pixel

        # Remove keys that are complete
        self._animations = [x for x in self._animations if not x.is_complete()]

        return leds

    def is_complete(self):
        return False
<commit_msg>Add animation that runs side to side.<commit_after>""" The various classes relating to animations """
from __future__ import print_function
from __future__ import division

import math

from random import randint
import time

class Animation(object):
    """The base class for any animation. An animation is a state machine that produces frames.
       Keep calling get_frame until is_complete returns true.
    """
    def __init__(self, milliseconds=None):
        """ Animation base class initializer

        Parameters
        ----------
        milliseconds : function, optional
            Optional function that returns the number of milliseconds elapsed. A default implementation
            is provided that uses the system time. Provide an alternative function if time must be
            externally controlled. This is useful in unit testing scenarios.
        """
        object.__init__(self)
        if milliseconds is None:
            self._milliseconds = lambda: int(round(time.time() * 1000))
        else:
            self._milliseconds = milliseconds

    def get_frame(self):
        """Return an array of tuples (r,g,b) i.e. the frame for the current state of the animation"""
        raise RuntimeError("GetFrame should only be called in derived classes")

    def is_complete(self):
        """True if this animation is complete and can be removed"""
        return False

class LeftRightAnimation(Animation):
    """ Light runs side to side """
    def __init__(self, milliseconds, length, frames_per_second):
        """
        Parameters
        ----------
        length : integer
        The number of lights in the animation
        """
        Animation.__init__(self, milliseconds)
        self._ = [length]
        self._index = 0
        self._last_frame_time = 0
        self._milliseconds_per_frame = 1000 / frames_per_second
        self._direction = 1

    def get_frame(self):
        now = self._milliseconds()
        if now - self._last_frame_time > self._milliseconds_per_frame:
            self._last_frame_time = now
            self._index += self._direction
            leds = [(0, 0, 0)] * 88

        return self._lights

class FireAnimation(Animation):
    """ Fire animation """
    def __init__(self):
        Animation.__init__(self)
        self._lights = []
        self._r = 255
        self._g = 255 - 40
        self._b = 40
        self._end = 0

    def get_frame(self):
        if self._milliseconds() > self._end:
            self._end = self._milliseconds() + 50
            self._lights = []
            for _ in range(0, 88):
                flicker = randint(0, 150)
                r1 = self._r - flicker
                g1 = self._g - flicker
                b1 = self._b - flicker
                if r1 < 0:
                    r1 = 0
                if g1 < 0:
                    g1 = 0
                if b1 < 0:
                    b1 = 0
                self._lights.append((r1, g1, b1))
        return self._lights

    def is_complete(self):
        return False

class BeatAnimation(Animation):
    """Lights up on a specific beat"""
    def __init__(self, width, bpm, milliseconds=None):
        Animation.__init__(self, milliseconds=None)
        self._ms_per_beat = 1000 / (bpm / 60)
        self._current_pulse_time = self._milliseconds()
        self._width = width
        self._bell_curve = BeatAnimation.create_bell_curve(width)

    @classmethod
    def create_bell_curve(cls, width):
        """ Create a bell curve with width elements and values between 0 and 1.
            The standard deviation value of 0.4 means the curve will peak at 1.
            Starting at around -1.5 to 1.5 gives a nice ramp up and down."""

        # Need to step between -1.5 and 1.5
        step = 2.0 / width
        x = -1
        curve = []

        for _ in range(width):
            curve.append(cls.normpdf(x, 0, 0.4))
            x += step
        return curve

    def get_frame(self):
        now = self._milliseconds()
        time_into_beat = now % self._ms_per_beat

        # Brightness decreases as time progresses into the beat. Adjust to an interval between 0-255.
        brightness = int((self._ms_per_beat - time_into_beat) / self._ms_per_beat * 256)
        pixels = [(brightness, brightness, brightness)] * self._width

        # Apply a bell curve to pixels - this avoids all of them lighting up and instead a soft ramp up and ramp down
        for i, (r, g, b) in enumerate(pixels):
            factor = self._bell_curve[i]
            pixels[i] = (int(r * factor), int(g * factor), int(b * factor))
        return pixels

    def is_complete(self):
        return False

    @classmethod
    def normpdf(cls, x, mean, standard_deviation):
        """ Calculates the normal distribution using a probability density function
            Found it here https://stackoverflow.com/a/12413491 """
        var = float(standard_deviation)**2
        pi = 3.1415926
        denom = (2*pi*var)**.5
        num = math.exp(-(float(x)-float(mean))**2/(2*var))
        return num/denom

class LightUpAnimation(Animation):
    """Simple animation that lights up the given key for a short period of time"""

    def __init__(self, keys, key_pressed, duration=1000, milliseconds=None):
        """Initializes a new LightUpAnimation instance"""
        Animation.__init__(self)
        self._end = self._milliseconds() + duration
        self._leds = [(0, 0, 0)] * keys
        self._key_pressed = key_pressed

    def get_frame(self):
        """Return an array of integers representing the current state of the animation"""
        self._leds[self._key_pressed] = (255, 255, 255)
        return self._leds

    def is_complete(self):
        """True if this animation is complete and can be removed"""
        return self._milliseconds() > self._end

class PressureKeyPressAnimation(LightUpAnimation):
    """Simple animation that happens when you press a key. It is pressure sensitive."""

    def __init__(self, keys, key_pressed, velocity, duration=1000, milliseconds=None):
        """Initializes a new PressureKeyPressAnimation instance"""
        LightUpAnimation.__init__(self, keys, key_pressed, duration, milliseconds)
        self._velocity = velocity
        self._duration = duration

    def get_key_color(self):
        """Returns the color of the key pressed during animation. Override to change."""
        return (self._velocity, self._velocity, self._velocity)

    def get_frame(self):
        """Return an array of integers representing the current state of the animation."""

        time_left = self._end - self._milliseconds()
        if time_left < 0:
            time_left = 0

        r, g, b = self.get_key_color()
        fade_factor = time_left / self._duration
        r = int(r * fade_factor)
        g = int(g * fade_factor)
        b = int(b * fade_factor)

        self._leds[self._key_pressed] = (r, g, b)
        return self._leds

class RunLeftAnimation(Animation):
    """Simple animation that happens when you press a key"""

    def __init__(self, key_pressed):
        """Initializes a new KeyPressAnimation instance"""
        Animation.__init__(self)
        self._key_pressed = key_pressed
        r = randint(0, 3)
        if r == 0:
            self._color = (255, 0, 0)
        if r == 1:
            self._color = (255, 255, 255)
        if r == 2:
            self._color = (255, 255, 0)
        if r == 3:
            self._color = (0, 255, 255)

    def get_frame(self):
        """Return an array of integers representing the current state of the animation"""
        leds = [(0, 0, 0)] * 88
        leds[self._key_pressed] = self._color
        self._key_pressed -= 1
        return leds

    def is_complete(self):
        """True if this animation is complete and can be removed"""
        return self._key_pressed < 0

class ChristmasKeyPressAnimation(PressureKeyPressAnimation):
    """Simple animation that happens when you press a key. It is pressure sensitive."""

    def __init__(self, keys, key_pressed, velocity, duration=1000):
        """Initializes a new ChristmasKeyPressAnimation instance"""
        PressureKeyPressAnimation.__init__(self, keys, key_pressed, velocity, duration)
        color = randint(0, 2)

        if color == 0:
            self._color = (velocity, 0, 0)
        if color == 1:
            self._color = (0, velocity, 0)
        if color == 2:
            self._color = (velocity, velocity, velocity)

    def get_key_color(self):
        """Overrides the default and return a Christmasey color"""
        return self._color

class RunningAnimation(Animation):
    """Animation the moves each time a key is pressed"""
    def __init__(self, keys, milliseconds=None):
        Animation.__init__(self, milliseconds)
        # This will hold the active key animations
        self._animations = []
        self._keys = keys
        self._key = 0

    def key_pressed(self, velocity):
        """Call whenever a key is pressed"""
        self._animations.append(PressureKeyPressAnimation(self._keys, self._key, velocity, 1000, self._milliseconds))
        self._key = self._key + 1
        self._key = self._key % self._keys

    def get_frame(self):
        leds = [(0, 0, 0)] * self._keys
        for current_animation in self._animations:
            new_frame = current_animation.get_frame()
            for i, frame_pixel in enumerate(new_frame):
                r, g, b = (frame_pixel)
                if r > 0 or g > 0 or b > 0:
                    leds[i] = frame_pixel

        # Remove keys that are complete
        self._animations = [x for x in self._animations if not x.is_complete()]

        return leds

    def is_complete(self):
        return False
<|endoftext|>


<commit_before>"""
Compute the splice graph from a transcriptome and raw genomic reads using bloom
filters.
"""

__version__ = '1.4.4'
<commit_msg>Version bump<commit_after>"""
Compute the splice graph from a transcriptome and raw genomic reads using bloom
filters.
"""

__version__ = '1.4.5'
<|endoftext|>


<commit_before>import simplejson as json
from mongrel2 import handler

sender_id = "82209006-86FF-4982-B5EA-D1E29E55D481"

conn = handler.Connection(sender_id, "tcp://127.0.0.1:10000",
                          "tcp://127.0.0.1:9998")
users = {}
user_list = []

while True:
    try:
        req = conn.recv_json()
    except:
        print "FAILED RECV JSON"
        continue

    data = req.data

    print "DATA", data, req.conn_id

    if data["type"] == "join":
        conn.deliver_json(req.sender, users.keys(), data)
        users[req.conn_id] = data['user']
        user_list = [u[1] for u in users.items()]
        conn.reply_json(req, {'type': 'userList', 'users': user_list})

    elif data["type"] == "disconnect":
        print "DISCONNECTED", req.conn_id

        if req.conn_id in users:
            data['user'] = users[req.conn_id]
            del users[req.conn_id]

        if len(users.keys()) > 0:
            conn.deliver_json(req.sender, users.keys(), data)
            user_list = [u[1] for u in users.items()]

    elif req.conn_id not in users:
        users[req.conn_id] = data['user']

    elif data['type'] == "msg":
        conn.deliver_json(req.sender, users.keys(), data)

    print "REGISTERED USERS:", len(users)

<commit_msg>Moved the chat port around a bit.<commit_after>import simplejson as json
from mongrel2 import handler

sender_id = "82209006-86FF-4982-B5EA-D1E29E55D481"

conn = handler.Connection(sender_id, "tcp://127.0.0.1:9999",
                          "tcp://127.0.0.1:9998")
users = {}
user_list = []

while True:
    try:
        req = conn.recv_json()
    except:
        print "FAILED RECV JSON"
        continue

    data = req.data

    print "DATA", data, req.conn_id

    if data["type"] == "join":
        conn.deliver_json(req.sender, users.keys(), data)
        users[req.conn_id] = data['user']
        user_list = [u[1] for u in users.items()]
        conn.reply_json(req, {'type': 'userList', 'users': user_list})

    elif data["type"] == "disconnect":
        print "DISCONNECTED", req.conn_id

        if req.conn_id in users:
            data['user'] = users[req.conn_id]
            del users[req.conn_id]

        if len(users.keys()) > 0:
            conn.deliver_json(req.sender, users.keys(), data)
            user_list = [u[1] for u in users.items()]

    elif req.conn_id not in users:
        users[req.conn_id] = data['user']

    elif data['type'] == "msg":
        conn.deliver_json(req.sender, users.keys(), data)

    print "REGISTERED USERS:", len(users)

<|endoftext|>


<commit_before><commit_msg>Delete test_dihedral_harmonic.py<commit_after><|endoftext|>


<commit_before>#!/usr/bin/env python
# -*- coding: utf-8 -*-

import dynet

from teras.app import App, arg
import teras.dataset
from teras.framework.dynet import config as dynet_config
import teras.framework.dynet.functions as F
from teras.framework.dynet.model import MLP
import teras.logging as Log
from teras.training import Trainer
from teras.training.event import TrainEvent as Event

def train(n_epoch=20,
          batch_size=100,
          n_layers=3,
          n_units=1000,
          dropout=0.2):

    train, test = teras.dataset.get_mnist()
    train_x, train_y = train
    test_x, test_y = test

    Log.v('')
    Log.i('--------------------------------')
    Log.i('# Minibatch-size: {}'.format(batch_size))
    Log.i('# epoch: {}'.format(n_epoch))
    Log.i('# model: {}'.format(MLP))
    Log.i('# layer: {}'.format(n_layers))
    Log.i('# unit: {}'.format(n_units))
    Log.i('# dropout: {}'.format(dropout))
    Log.i('--------------------------------')
    Log.v('')

    assert n_layers >= 1
    if n_layers == 1:
        layers = [MLP.Layer(784, 10)]
    else:
        layers = [MLP.Layer(784, n_units, dynet.rectify, dropout)]
        for i in range(n_layers - 2):
            layers.append(MLP.Layer(n_units, n_units, dynet.rectify, dropout))
        layers.append(MLP.Layer(n_units, 10))
    model = MLP(layers)
    params = dynet.ParameterCollection()
    model.init_params(params)

    optimizer = dynet.AdamTrainer(
        params, alpha=0.001, beta_1=0.9, beta_2=0.999, eps=1e-08, edecay=0.0)
    Log.i('optimizer: Adam(alpha=0.001, beta_1=0.9, beta_2=0.999, '
          'eps=1e-08, edecay=0.0)')

    def forward(x):
        x = dynet.inputTensor(x.T, batched=True)
        return model(x)

    trainer = Trainer(optimizer, forward, loss_func=F.nll_loss,
                      accuracy_func=F.accuracy)
    trainer.configure(dynet_config)
    trainer.add_hook(Event.EPOCH_TRAIN_END,
                     lambda data: optimizer.update_epoch())
    trainer.fit(train_x, train_y,
                batch_size=batch_size,
                epochs=n_epoch,
                validation_data=(test_x, test_y))

def decode():
    """define decode command"""
    pass

App.add_command('train', train, {
    'batch_size':
    arg('--batchsize', '-b', type=int, default=100,
        help='Number of examples in each mini-batch',
        metavar='SIZE'),
    'dropout':
    arg('--dropout', '-dr', type=float, default=0.2,
        help='dropout ratio', metavar='RATIO'),
    'n_epoch':
    arg('--epoch', '-e', type=int, default=20,
        help='Number of sweeps over the dataset to train',
        metavar='NUM'),
    'n_layers':
    arg('--layer', '-l', type=int, default=3,
        help='Number of layers', metavar='NUM'),
    'n_units':
    arg('--unit', '-u', type=int, default=1000,
        help='Number of units', metavar='NUM')
}, description="exec train")

App.add_command('decode', decode, {})

if __name__ == "__main__":
    App.configure(name='dynet-mnist', logoption='d')
    App.run()
<commit_msg>fix dynet example.<commit_after>#!/usr/bin/env python
# -*- coding: utf-8 -*-

try:
    import _dynet
    dyparams = _dynet.DynetParams()
    dyparams.set_mem(2048)
    dyparams.init()
except Exception:
    pass
import dynet

from teras.app import App, arg
import teras.dataset
from teras.framework.dynet import config as dynet_config
import teras.framework.dynet.functions as F
from teras.framework.dynet.model import MLP
import teras.logging as Log
from teras.training import Trainer

def train(n_epoch=20,
          batch_size=100,
          n_layers=3,
          n_units=1000,
          dropout=0.2):

    train, test = teras.dataset.get_mnist()
    train_x, train_y = train
    test_x, test_y = test

    Log.v('')
    Log.i('--------------------------------')
    Log.i('# Minibatch-size: {}'.format(batch_size))
    Log.i('# epoch: {}'.format(n_epoch))
    Log.i('# model: {}'.format(MLP))
    Log.i('# layer: {}'.format(n_layers))
    Log.i('# unit: {}'.format(n_units))
    Log.i('# dropout: {}'.format(dropout))
    Log.i('--------------------------------')
    Log.v('')

    assert n_layers >= 1
    if n_layers == 1:
        layers = [MLP.Layer(784, 10)]
    else:
        layers = [MLP.Layer(784, n_units, dynet.rectify, dropout)]
        for i in range(n_layers - 2):
            layers.append(MLP.Layer(n_units, n_units, dynet.rectify, dropout))
        layers.append(MLP.Layer(n_units, 10))
    model = MLP(layers)
    params = dynet.ParameterCollection()
    model.init_params(params)

    optimizer = dynet.AdamTrainer(
        params, alpha=0.001, beta_1=0.9, beta_2=0.999, eps=1e-08)
    Log.i('optimizer: Adam(alpha=0.001, beta_1=0.9, beta_2=0.999, eps=1e-08)')

    def forward(x):
        x = dynet.inputTensor(x.T, batched=True)
        return model(x)

    trainer = Trainer(optimizer, forward, loss_func=F.nll_loss,
                      accuracy_func=F.accuracy)
    trainer.configure(dynet_config)
    trainer.fit(train_x, train_y,
                batch_size=batch_size,
                epochs=n_epoch,
                validation_data=(test_x, test_y))

def decode():
    """define decode command"""
    pass

App.add_command('train', train, {
    'batch_size':
    arg('--batchsize', '-b', type=int, default=100,
        help='Number of examples in each mini-batch',
        metavar='SIZE'),
    'dropout':
    arg('--dropout', '-dr', type=float, default=0.2,
        help='dropout ratio', metavar='RATIO'),
    'n_epoch':
    arg('--epoch', '-e', type=int, default=20,
        help='Number of sweeps over the dataset to train',
        metavar='NUM'),
    'n_layers':
    arg('--layer', '-l', type=int, default=3,
        help='Number of layers', metavar='NUM'),
    'n_units':
    arg('--unit', '-u', type=int, default=1000,
        help='Number of units', metavar='NUM')
}, description="exec train")

App.add_command('decode', decode, {})

if __name__ == "__main__":
    App.configure(name='dynet-mnist', logoption='d')
    App.run()
<|endoftext|>