<commit_before>import errno
import fcntl
import os
import signal
import sys
import time
import traceback

import fs
import genlog
import sockinherit

logger = genlog.logger

class Daemon:
    """
    A generic daemon class.

    Usage: subclass the Daemon class and override the run() method
    """

    def __init__(self, pidfile, run=lambda: None,
                 stdin='/dev/null', stdout='/dev/null', stderr='/dev/null', foreground=False):

        self._run = run
        self.stdin = stdin
        self.stdout = stdout
        self.stderr = stderr
        self.pidfile = pidfile
        # NOTE: We need to open another separate file to avoid the file
        #       reopened # again. Which case, process lose file lock.
        #
        # From "man fcntl":
        # As well as being removed by an explicit F_UNLCK, record locks are
        # automatically released when the process terminates  or  if  it
        # closes  any  file descriptor  referring  to  a  file  on which locks
        # are held.  This is bad: it means that a process can lose the locks
        # on a file like /etc/passwd or /etc/mtab when for some reason a
        # library function decides to open, read and close it.
        self.lockfile = pidfile + ".lock"
        self.lockfp = None
        self.foreground = foreground

    def daemonize(self):
        """
        do the UNIX double-fork magic, see Stevens' "Advanced
        Programming in the UNIX Environment" for details (ISBN 0201563177)
        http://www.erlenstar.demon.co.uk/unix/faq_2.html#SEC16
        """

        if self.foreground:
            return

        try:

            pid = os.fork()
            if pid > 0:
                # exit first parent
                sys.exit(0)

        except OSError as e:

            sys.stderr.write("fork #1 failed: %d (%s)\n"
                             % (e.errno, e.strerror))
            sys.exit(1)

        # decouple from parent environment
        # os.chdir("/")
        os.setsid()
        os.umask(0)

        # do second fork
        try:

            pid = os.fork()
            if pid > 0:
                # exit from second parent
                sys.exit(0)

        except OSError as e:

            sys.stderr.write("fork #2 failed: %d (%s)\n"
                             % (e.errno, e.strerror))
            sys.exit(1)

        # redirect standard file descriptors
        sys.stdout.flush()
        sys.stderr.flush()
        si = file(self.stdin, 'r')
        so = file(self.stdout, 'a+')
        se = file(self.stderr, 'a+', 0)
        os.dup2(si.fileno(), sys.stdin.fileno())
        os.dup2(so.fileno(), sys.stdout.fileno())
        os.dup2(se.fileno(), sys.stderr.fileno())

        logger.info("OK daemonized")

    def trylock_or_exit(self, timeout=10):

        interval = 0.1
        n = int(timeout / interval) + 1
        flag = fcntl.LOCK_EX | fcntl.LOCK_NB

        for ii in range(n):

            fd = os.open(self.lockfile, os.O_RDWR | os.O_CREAT)

            fcntl.fcntl(fd, fcntl.F_SETFD,
                        fcntl.fcntl(fd, fcntl.F_GETFD, 0)
                        | fcntl.FD_CLOEXEC)

            try:
                fcntl.lockf(fd, flag)

                self.lockfp = os.fdopen(fd, 'w+r')
                break

            except IOError as e:
                os.close(fd)
                if e[0] == errno.EAGAIN:
                    time.sleep(interval)
                else:
                    raise

        else:
            genlog.logger.info("Failure acquiring lock %s" % (self.lockfile, ))
            sys.exit(1)

        genlog.logger.info("OK acquired lock %s" % (self.lockfile))

    def unlock(self):

        if self.lockfp is None:
            return

        fd = self.lockfp.fileno()
        fcntl.lockf(fd, fcntl.LOCK_UN)
        self.lockfp.close()
        self.lockfp = None

    def start(self):

        self.daemonize()
        self.init_proc()
        self.run()

    def init_proc(self):
        self.trylock_or_exit()
        self.write_pid_or_exit()

    def write_pid_or_exit(self):

        self.pf = open(self.pidfile, 'w+r')
        pf = self.pf

        fd = pf.fileno()
        fcntl.fcntl(fd, fcntl.F_SETFD,
                    fcntl.fcntl(fd, fcntl.F_GETFD, 0)
                    | fcntl.FD_CLOEXEC)

        try:
            pid = os.getpid()
            genlog.logger.debug('write pid:' + str(pid))

            pf.truncate(0)
            pf.write(str(pid))
            pf.flush()
        except Exception as e:
            genlog.logger.error('write pid failed.' + repr(e))
            sys.exit(0)

    def stop_pid(self):
        return self.stop()

    def stop(self):

        pid = None
        if not os.path.exists(self.pidfile):

            genlog.logger.debug('pidfile not exist:' + self.pidfile)
            return

        while 1:

            try:
                pid = fs.read_file(self.pidfile)
                pid = int(pid)
                os.kill(pid, signal.SIGTERM)
                return

            except Exception as e:
                genlog.logger.debug('get pid failed.' + str(e) + str(pid))
                # file been deleted?
                break

            time.sleep(0.1)

    def restart(self):
        """
        Restart the daemon
        """

        self.stop()
        self.start()

    def run(self):
        """
        You should override this method when you subclass Daemon.
        It will be called after the process has been
        daemonized by start() or restart().
        """

        self._run()

        return

def standard_daemonize(run_func, pidfn,
                       inheritable=None,
                       upgrade_arg=None,
                       cleanup=None):

    d = Daemon(pidfn, None)

    logger.info("sys.argv: " + repr(sys.argv))

    try:
        if len(sys.argv) == 1:
            d.init_proc()
            run_func()

        elif len(sys.argv) == 2:

            if 'start' == sys.argv[1]:
                d.daemonize()
                if inheritable is not None:
                    sockinherit.init_inheritable(inheritable)
                    install_upgrade_sig(d, inheritable, upgrade_arg, cleanup)

                d.init_proc()
                run_func()

            elif 'stop' == sys.argv[1]:
                d.stop_pid()

            elif 'restart' == sys.argv[1]:
                if inheritable is None:
                    d.stop_pid()
                    d.daemonize()
                    d.init_proc()
                else:
                    signal_to_upgrade(pidfn)
                    # if it returns, upgrade failed. fall back to normal
                    # restart.

                    d.stop_pid()

                    d.daemonize()
                    sockinherit.init_inheritable(inheritable)
                    install_upgrade_sig(d, inheritable, upgrade_arg, cleanup)
                    d.init_proc()

                run_func()

            else:
                logger.error("Unknown command: %s" % (sys.argv[1]))
                print "Unknown command"
                sys.exit(2)

            sys.exit(0)
        else:
            print "usage: %s start|stop|restart" % sys.argv[0]
            sys.exit(2)

    except Exception as e:
        logger.error(traceback.format_exc())
        logger.error(repr(e))

def signal_to_upgrade(pidFile):

    pid = _get_pid(pidFile)
    logger.info("old pid: " + repr(pid))

    if pid is not None:

        try:
            os.kill(pid, signal.SIGUSR2)
        except OSError as e:
            # no such process
            return

        logger.info("SIGUSR2 sent to: " + repr(pid))

        for ii in range(30):
            time.sleep(0.1)
            pid2 = _get_pid(pidFile)
            if pid2 is not None and pid != pid2:
                logger.info("new pid generated, upgrade succeed: "
                            + repr(pid2))
                sys.exit(0)

def _get_pid(fn):

    try:
        with open(fn, 'r') as f:
            cont = f.read()
    except OSError as e:
        return None

    try:
        return int(cont)
    except ValueError as e:
        return None

def install_upgrade_sig(d, inheritable, upgrade_arg, cleanup):

    heir = {}
    for name, val in inheritable.items():
        heir[name] = val['sock'].fileno()

    def sig_up(*args, **argkv):
        if callable(upgrade_arg):
            exe, args, cwd = upgrade_arg()
        else:
            exe, args, cwd = upgrade_arg

        sockinherit.upgrade(exe, args, cwd, heir)

        logger.info("parent spwaned new process")
        logger.info("parent sleep 1 second")
        time.sleep(1)

        d.unlock()
        logger.info("parent released lock, about to exit")

        (cleanup or sys.exit)()

    signal.signal(signal.SIGUSR2, sig_up)
<commit_msg>remove all genlog.logger.xx(), use logger.xx()<commit_after>import errno
import fcntl
import os
import signal
import sys
import time
import traceback

import fs
import genlog
import sockinherit

logger = genlog.logger

class Daemon:
    """
    A generic daemon class.

    Usage: subclass the Daemon class and override the run() method
    """

    def __init__(self, pidfile, run=lambda: None,
                 stdin='/dev/null', stdout='/dev/null', stderr='/dev/null', foreground=False):

        self._run = run
        self.stdin = stdin
        self.stdout = stdout
        self.stderr = stderr
        self.pidfile = pidfile
        # NOTE: We need to open another separate file to avoid the file
        #       reopened # again. Which case, process lose file lock.
        #
        # From "man fcntl":
        # As well as being removed by an explicit F_UNLCK, record locks are
        # automatically released when the process terminates  or  if  it
        # closes  any  file descriptor  referring  to  a  file  on which locks
        # are held.  This is bad: it means that a process can lose the locks
        # on a file like /etc/passwd or /etc/mtab when for some reason a
        # library function decides to open, read and close it.
        self.lockfile = pidfile + ".lock"
        self.lockfp = None
        self.foreground = foreground

    def daemonize(self):
        """
        do the UNIX double-fork magic, see Stevens' "Advanced
        Programming in the UNIX Environment" for details (ISBN 0201563177)
        http://www.erlenstar.demon.co.uk/unix/faq_2.html#SEC16
        """

        if self.foreground:
            return

        try:

            pid = os.fork()
            if pid > 0:
                # exit first parent
                sys.exit(0)

        except OSError as e:

            sys.stderr.write("fork #1 failed: %d (%s)\n"
                             % (e.errno, e.strerror))
            sys.exit(1)

        # decouple from parent environment
        # os.chdir("/")
        os.setsid()
        os.umask(0)

        # do second fork
        try:

            pid = os.fork()
            if pid > 0:
                # exit from second parent
                sys.exit(0)

        except OSError as e:

            sys.stderr.write("fork #2 failed: %d (%s)\n"
                             % (e.errno, e.strerror))
            sys.exit(1)

        # redirect standard file descriptors
        sys.stdout.flush()
        sys.stderr.flush()
        si = file(self.stdin, 'r')
        so = file(self.stdout, 'a+')
        se = file(self.stderr, 'a+', 0)
        os.dup2(si.fileno(), sys.stdin.fileno())
        os.dup2(so.fileno(), sys.stdout.fileno())
        os.dup2(se.fileno(), sys.stderr.fileno())

        logger.info("OK daemonized")

    def trylock_or_exit(self, timeout=10):

        interval = 0.1
        n = int(timeout / interval) + 1
        flag = fcntl.LOCK_EX | fcntl.LOCK_NB

        for ii in range(n):

            fd = os.open(self.lockfile, os.O_RDWR | os.O_CREAT)

            fcntl.fcntl(fd, fcntl.F_SETFD,
                        fcntl.fcntl(fd, fcntl.F_GETFD, 0)
                        | fcntl.FD_CLOEXEC)

            try:
                fcntl.lockf(fd, flag)

                self.lockfp = os.fdopen(fd, 'w+r')
                break

            except IOError as e:
                os.close(fd)
                if e[0] == errno.EAGAIN:
                    time.sleep(interval)
                else:
                    raise

        else:
            logger.info("Failure acquiring lock %s" % (self.lockfile, ))
            sys.exit(1)

        logger.info("OK acquired lock %s" % (self.lockfile))

    def unlock(self):

        if self.lockfp is None:
            return

        fd = self.lockfp.fileno()
        fcntl.lockf(fd, fcntl.LOCK_UN)
        self.lockfp.close()
        self.lockfp = None

    def start(self):

        self.daemonize()
        self.init_proc()
        self.run()

    def init_proc(self):
        self.trylock_or_exit()
        self.write_pid_or_exit()

    def write_pid_or_exit(self):

        self.pf = open(self.pidfile, 'w+r')
        pf = self.pf

        fd = pf.fileno()
        fcntl.fcntl(fd, fcntl.F_SETFD,
                    fcntl.fcntl(fd, fcntl.F_GETFD, 0)
                    | fcntl.FD_CLOEXEC)

        try:
            pid = os.getpid()
            logger.debug('write pid:' + str(pid))

            pf.truncate(0)
            pf.write(str(pid))
            pf.flush()
        except Exception as e:
            logger.error('write pid failed.' + repr(e))
            sys.exit(0)

    def stop_pid(self):
        return self.stop()

    def stop(self):

        pid = None
        if not os.path.exists(self.pidfile):

            logger.debug('pidfile not exist:' + self.pidfile)
            return

        while 1:

            try:
                pid = fs.read_file(self.pidfile)
                pid = int(pid)
                os.kill(pid, signal.SIGTERM)
                return

            except Exception as e:
                logger.debug('get pid failed.' + str(e) + str(pid))
                # file been deleted?
                break

            time.sleep(0.1)

    def restart(self):
        """
        Restart the daemon
        """

        self.stop()
        self.start()

    def run(self):
        """
        You should override this method when you subclass Daemon.
        It will be called after the process has been
        daemonized by start() or restart().
        """

        self._run()

        return

def standard_daemonize(run_func, pidfn,
                       inheritable=None,
                       upgrade_arg=None,
                       cleanup=None):

    d = Daemon(pidfn, None)

    logger.info("sys.argv: " + repr(sys.argv))

    try:
        if len(sys.argv) == 1:
            d.init_proc()
            run_func()

        elif len(sys.argv) == 2:

            if 'start' == sys.argv[1]:
                d.daemonize()
                if inheritable is not None:
                    sockinherit.init_inheritable(inheritable)
                    install_upgrade_sig(d, inheritable, upgrade_arg, cleanup)

                d.init_proc()
                run_func()

            elif 'stop' == sys.argv[1]:
                d.stop_pid()

            elif 'restart' == sys.argv[1]:
                if inheritable is None:
                    d.stop_pid()
                    d.daemonize()
                    d.init_proc()
                else:
                    signal_to_upgrade(pidfn)
                    # if it returns, upgrade failed. fall back to normal
                    # restart.

                    d.stop_pid()

                    d.daemonize()
                    sockinherit.init_inheritable(inheritable)
                    install_upgrade_sig(d, inheritable, upgrade_arg, cleanup)
                    d.init_proc()

                run_func()

            else:
                logger.error("Unknown command: %s" % (sys.argv[1]))
                print "Unknown command"
                sys.exit(2)

            sys.exit(0)
        else:
            print "usage: %s start|stop|restart" % sys.argv[0]
            sys.exit(2)

    except Exception as e:
        logger.error(traceback.format_exc())
        logger.error(repr(e))

def signal_to_upgrade(pidFile):

    pid = _get_pid(pidFile)
    logger.info("old pid: " + repr(pid))

    if pid is not None:

        try:
            os.kill(pid, signal.SIGUSR2)
        except OSError:
            # no such process
            return

        logger.info("SIGUSR2 sent to: " + repr(pid))

        for ii in range(30):
            time.sleep(0.1)
            pid2 = _get_pid(pidFile)
            if pid2 is not None and pid != pid2:
                logger.info("new pid generated, upgrade succeed: "
                            + repr(pid2))
                sys.exit(0)

def _get_pid(fn):

    try:
        with open(fn, 'r') as f:
            cont = f.read()
    except OSError:
        return None

    try:
        return int(cont)
    except ValueError:
        return None

def install_upgrade_sig(d, inheritable, upgrade_arg, cleanup):

    heir = {}
    for name, val in inheritable.items():
        heir[name] = val['sock'].fileno()

    def sig_up(*args, **argkv):
        if callable(upgrade_arg):
            exe, args, cwd = upgrade_arg()
        else:
            exe, args, cwd = upgrade_arg

        sockinherit.upgrade(exe, args, cwd, heir)

        logger.info("parent spwaned new process")
        logger.info("parent sleep 1 second")
        time.sleep(1)

        d.unlock()
        logger.info("parent released lock, about to exit")

        (cleanup or sys.exit)()

    signal.signal(signal.SIGUSR2, sig_up)
<|endoftext|>


<commit_before>import datetime
import functools
import locale
import re
from contextlib import contextmanager
from typing import Hashable, Iterable, Tuple, Union

import dateparser
from dateparser.languages.detection import AutoDetectLanguage
from django.utils.translation import get_language_info
from iso8601 import iso8601

DEFAULT_DATEPARSER_SETTINGS = {
    'PREFER_DAY_OF_MONTH': 'first',
    "RETURN_AS_TIMEZONE_AWARE": False
}

RE_ISO = re.compile(r'\d{4}-\d{2}-\d{2}')

def _get_language_aliases(language: dateparser.languages.Language) -> Iterable[str]:
    yield language.info['name']
    yield language.shortname
    try:
        yield get_language_info(language.shortname)['name_local']
    except KeyError:
        pass

_language_aliases = dict((alias.lower(), l)
                         for l in dateparser.languages.default_language_loader.get_languages()
                         for alias in _get_language_aliases(l))

def read_date(datestr: str, language_pool: Iterable[str] = None) -> Union[None, datetime.datetime]:
    """
    Parses a date, and returns the datetime object. If a language pool is given, only the given
    languages will be considered. Otherwise, all languages known to the dateparser library will be used.

    @param datestr: The string containing the date

    @param language_pool:   An iterable of language identifiers. An identifier is case insensitive,
                            and should be one of:
                             - the ISO 639-1 code
                             - the English name
                             - the local name, as known by Django's translation library
    @return None
    """
    if language_pool is not None:
        language_pool = tuple(language_pool)

    return _read_date(datestr, language_pool)

@functools.lru_cache()
def _get_dateparser(language_pool: Tuple[str, ...], settings: Hashable = None) -> dateparser.DateDataParser:
    settings = dict(settings or ())
    parser = dateparser.DateDataParser(allow_redetect_language=True, settings=settings)

    if language_pool is None:
        return parser

    language_codes = set(_language_aliases[lang.lower()]
                         for lang in language_pool
                         if lang in _language_aliases)

    if not language_codes:
        # language pool None or empty, fall back to the default language pool.
        return parser

    lang_detector = AutoDetectLanguage(list(language_codes), allow_redetection=True)
    parser.language_detector = lang_detector

    return parser

def _parse_with_language_pool(datestr: str, language_pool: Tuple[str, ...], **settings_kwargs) -> datetime.datetime:
    """
    Gets a DateDataParser with an AutoDetectLanguage language detector using the given language pool.

    @param datestr:         The date string that should be parsed.
    @param language_pool:   A tuple of language names. The names are case insensitive. A name should be one of:
                                - the ISO 639-1 code
                                - the English name
                                - the local name, as known by Django's translation library

    @param settings_kwargs: These kwargs are added to DateParser's settings dict. See the documentation of
                            the DateParser library for details.

    @return: The parsed date
    """
    settings = tuple(dict(DEFAULT_DATEPARSER_SETTINGS, **settings_kwargs).items())
    dateparser = _get_dateparser(language_pool, settings)
    date = dateparser.get_date_data(datestr)
    if date:
        return date['date_obj']

@contextmanager
def _temp_locale(category, loc=(None, None)):
    _old = locale.getlocale(category)
    try:
        locale.setlocale(category, loc)
        yield
    finally:
        locale.setlocale(category, _old)

@functools.lru_cache()
def _read_date(datestr: str, language_pool: Tuple[str, ...]):
    try:
        return iso8601.parse_date(datestr, default_timezone=None)
    except iso8601.ParseError:
        pass

    datestr = datestr.replace("Maerz", "März")  # Needed in LN parser?

    if RE_ISO.match(datestr):
        date_order = 'YMD'  # ISO-like but not quite ISO
    else:
        date_order = 'DMY'  # MDY is studid!

    with _temp_locale(locale.LC_TIME):
        language_pool = None if language_pool is None else tuple(language_pool)
        date = _parse_with_language_pool(datestr, language_pool=language_pool, DATE_ORDER=date_order)
    if date is None:
        raise ValueError("Could not parse datestr: {datestr!r}".format(**locals()))
    return date
<commit_msg>documentation typo in read_date<commit_after>import datetime
import functools
import locale
import re
from contextlib import contextmanager
from typing import Hashable, Iterable, Tuple, Union

import dateparser
from dateparser.languages.detection import AutoDetectLanguage
from django.utils.translation import get_language_info
from iso8601 import iso8601

DEFAULT_DATEPARSER_SETTINGS = {
    'PREFER_DAY_OF_MONTH': 'first',
    "RETURN_AS_TIMEZONE_AWARE": False
}

RE_ISO = re.compile(r'\d{4}-\d{2}-\d{2}')

def _get_language_aliases(language: dateparser.languages.Language) -> Iterable[str]:
    yield language.info['name']
    yield language.shortname
    try:
        yield get_language_info(language.shortname)['name_local']
    except KeyError:
        pass

_language_aliases = dict((alias.lower(), l)
                         for l in dateparser.languages.default_language_loader.get_languages()
                         for alias in _get_language_aliases(l))

def read_date(datestr: str, language_pool: Iterable[str] = None) -> Union[None, datetime.datetime]:
    """
    Parses a date, and returns the datetime object. If a language pool is given, only the given
    languages will be considered. Otherwise, all languages known to the dateparser library will be used.

    @param datestr: The string containing the date

    @param language_pool:   An iterable of language identifiers. An identifier is case insensitive,
                            and should be one of:
                             - the ISO 639-1 code
                             - the English name
                             - the local name, as known by Django's translation library
    @return: The resulting datetime
    """
    if language_pool is not None:
        language_pool = tuple(language_pool)

    return _read_date(datestr, language_pool)

@functools.lru_cache()
def _read_date(datestr: str, language_pool: Tuple[str, ...]):
    try:
        return iso8601.parse_date(datestr, default_timezone=None)
    except iso8601.ParseError:
        pass

    datestr = datestr.replace("Maerz", "März")  # Needed in LN parser?

    if RE_ISO.match(datestr):
        date_order = 'YMD'  # ISO-like but not quite ISO
    else:
        date_order = 'DMY'  # MDY is studid!

    with _temp_locale(locale.LC_TIME):
        language_pool = None if language_pool is None else tuple(language_pool)
        date = _parse_with_language_pool(datestr, language_pool=language_pool, DATE_ORDER=date_order)
    if date is None:
        raise ValueError("Could not parse datestr: {datestr!r}".format(**locals()))
    return date

@functools.lru_cache()
def _get_dateparser(language_pool: Tuple[str, ...], settings: Hashable = None) -> dateparser.DateDataParser:
    settings = dict(settings or ())
    parser = dateparser.DateDataParser(allow_redetect_language=True, settings=settings)

    if language_pool is None:
        return parser

    language_codes = set(_language_aliases[lang.lower()]
                         for lang in language_pool
                         if lang in _language_aliases)

    if not language_codes:
        # language pool None or empty, fall back to the default language pool.
        return parser

    lang_detector = AutoDetectLanguage(list(language_codes), allow_redetection=True)
    parser.language_detector = lang_detector

    return parser

def _parse_with_language_pool(datestr: str, language_pool: Tuple[str, ...], **settings_kwargs) -> datetime.datetime:
    settings = tuple(dict(DEFAULT_DATEPARSER_SETTINGS, **settings_kwargs).items())
    dateparser = _get_dateparser(language_pool, settings)
    date = dateparser.get_date_data(datestr)
    if date:
        return date['date_obj']

@contextmanager
def _temp_locale(category, loc=(None, None)):
    _old = locale.getlocale(category)
    try:
        locale.setlocale(category, loc)
        yield
    finally:
        locale.setlocale(category, _old)
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-
"""
Optimization algorithms for OT
"""

# Author: Remi Flamary <remi.flamary@unice.fr>
#         Titouan Vayer <titouan.vayer@irisa.fr>
# License: MIT License

import numpy as np
from scipy.optimize.linesearch import scalar_search_armijo
from .lp import emd
from .bregman import sinkhorn

# The corresponding scipy function does not work for matrices

def line_search_armijo(f, xk, pk, gfk, old_fval,
                       args=(), c1=1e-4, alpha0=0.99):
    """
    Armijo linesearch function that works with matrices

    find an approximate minimum of f(xk+alpha*pk) that satifies the
    armijo conditions.

    Parameters
    ----------

    f : function
        loss function
    xk : np.ndarray
        initial position
    pk : np.ndarray
        descent direction
    gfk : np.ndarray
        gradient of f at xk
    old_fval : float
        loss value at xk
    args : tuple, optional
        arguments given to f
    c1 : float, optional
        c1 const in armijo rule (>0)
    alpha0 : float, optional
        initial step (>0)

    Returns
    -------
    alpha : float
        step that satisfy armijo conditions
    fc : int
        nb of function call
    fa : float
        loss value at step alpha

    """
    xk = np.atleast_1d(xk)
    fc = [0]

    def phi(alpha1):
        fc[0] += 1
        return f(xk + alpha1 * pk, *args)

    if old_fval is None:
        phi0 = phi(0.)
    else:
        phi0 = old_fval

    derphi0 = np.sum(pk * gfk)  # Quickfix for matrices
    alpha, phi1 = scalar_search_armijo(
        phi, phi0, derphi0, c1=c1, alpha0=alpha0)

    return alpha, fc[0], phi1

def do_linesearch(cost, G, deltaG, Mi, f_val,
                  amijo=True, C1=None, C2=None, reg=None, Gc=None, constC=None, M=None):
    """
    Solve the linesearch in the FW iterations
    Parameters
    ----------
    cost : method
        The FGW cost
    G : ndarray, shape(ns,nt)
        The transport map at a given iteration of the FW
    deltaG : ndarray (ns,nt)
        Difference between the optimal map found by linearization in the FW algorithm and the value at a given iteration
    Mi : ndarray (ns,nt)
        Cost matrix of the linearized transport problem. Corresponds to the gradient of the cost
    f_val :  float
        Value of the cost at G
    amijo : bool, optionnal
            If True the steps of the line-search is found via an amijo research. Else closed form is used.
            If there is convergence issues use False.
    C1 : ndarray (ns,ns), optionnal
        Structure matrix in the source domain. Only used when amijo=False
    C2 : ndarray (nt,nt), optionnal
        Structure matrix in the target domain. Only used when amijo=False
    reg : float, optionnal
          Regularization parameter. Corresponds to the alpha parameter of FGW. Only used when amijo=False
    Gc : ndarray (ns,nt)
        Optimal map found by linearization in the FW algorithm. Only used when amijo=False
    constC : ndarray (ns,nt)
             Constant for the gromov cost. See [3]. Only used when amijo=False
    M : ndarray (ns,nt), optionnal
        Cost matrix between the features. Only used when amijo=False
    Returns
    -------
    alpha : float
            The optimal step size of the FW
    fc : int
         nb of function call. Useless here
    f_val :  float
             The value of the cost for the next iteration
    References
    ----------
    .. [24] Vayer Titouan, Chapel Laetitia, Flamary R{\'e}mi, Tavenard Romain
          and Courty Nicolas
        "Optimal Transport for structured data with application on graphs"
        International Conference on Machine Learning (ICML). 2019.
    """
    if amijo:
        alpha, fc, f_val = line_search_armijo(cost, G, deltaG, Mi, f_val)
    else:  # requires symetric matrices
        dot1 = np.dot(C1, deltaG)
        dot12 = dot1.dot(C2)
        a = -2 * reg * np.sum(dot12 * deltaG)
        b = np.sum((M + reg * constC) * deltaG) - 2 * reg * (np.sum(dot12 * G) + np.sum(np.dot(C1, G).dot(C2) * deltaG))
        c = cost(G)

        alpha = solve_1d_linesearch_quad_funct(a, b, c)
        fc = None
        f_val = cost(G + alpha * deltaG)

    return alpha, fc, f_val

def cg(a, b, M, reg, f, df, G0=None, numItermax=200,
       stopThr=1e-9, verbose=False, log=False, **kwargs):
    """
    Solve the general regularized OT problem with conditional gradient

        The function solves the following optimization problem:

    .. math::
        \gamma = arg\min_\gamma <\gamma,M>_F + reg*f(\gamma)

        s.t. \gamma 1 = a

             \gamma^T 1= b

             \gamma\geq 0
    where :

    - M is the (ns,nt) metric cost matrix
    - :math:`f` is the regularization term ( and df is its gradient)
    - a and b are source and target weights (sum to 1)

    The algorithm used for solving the problem is conditional gradient as discussed in  [1]_

    Parameters
    ----------
    a : np.ndarray (ns,)
        samples weights in the source domain
    b : np.ndarray (nt,)
        samples in the target domain
    M : np.ndarray (ns,nt)
        loss matrix
    reg : float
        Regularization term >0
    G0 :  np.ndarray (ns,nt), optional
        initial guess (default is indep joint density)
    numItermax : int, optional
        Max number of iterations
    stopThr : float, optional
        Stop threshol on error (>0)
    verbose : bool, optional
        Print information along iterations
    log : bool, optional
        record log if True
    kwargs : dict
             Parameters for linesearch

    Returns
    -------
    gamma : (ns x nt) ndarray
        Optimal transportation matrix for the given parameters
    log : dict
        log dictionary return only if log==True in parameters

    References
    ----------

    .. [1] Ferradans, S., Papadakis, N., Peyré, G., & Aujol, J. F. (2014). Regularized discrete optimal transport. SIAM Journal on Imaging Sciences, 7(3), 1853-1882.

    See Also
    --------
    ot.lp.emd : Unregularized optimal ransport
    ot.bregman.sinkhorn : Entropic regularized optimal transport

    """

    loop = 1

    if log:
        log = {'loss': []}

    if G0 is None:
        G = np.outer(a, b)
    else:
        G = G0

    def cost(G):
        return np.sum(M * G) + reg * f(G)

    f_val = cost(G)
    if log:
        log['loss'].append(f_val)

    it = 0

    if verbose:
        print('{:5s}|{:12s}|{:8s}'.format(
            'It.', 'Loss', 'Delta loss') + '\n' + '-' * 32)
        print('{:5d}|{:8e}|{:8e}'.format(it, f_val, 0))

    while loop:

        it += 1
        old_fval = f_val

        # problem linearization
        Mi = M + reg * df(G)
        # set M positive
        Mi += Mi.min()

        # solve linear program
        Gc = emd(a, b, Mi)

        deltaG = Gc - G

        # line search
        alpha, fc, f_val = do_linesearch(cost, G, deltaG, Mi, f_val, reg=reg, M=M, Gc=Gc, **kwargs)

        G = G + alpha * deltaG

        # test convergence
        if it >= numItermax:
            loop = 0

        delta_fval = (f_val - old_fval) / abs(f_val)
        if abs(delta_fval) < stopThr:
            loop = 0

        if log:
            log['loss'].append(f_val)

        if verbose:
            if it % 20 == 0:
                print('{:5s}|{:12s}|{:8s}'.format(
                    'It.', 'Loss', 'Delta loss') + '\n' + '-' * 32)
            print('{:5d}|{:8e}|{:8e}'.format(it, f_val, delta_fval))

    if log:
        return G, log
    else:
        return G

def gcg(a, b, M, reg1, reg2, f, df, G0=None, numItermax=10,
        numInnerItermax=200, stopThr=1e-9, verbose=False, log=False):
    """
    Solve the general regularized OT problem with the generalized conditional gradient

        The function solves the following optimization problem:

    .. math::
        \gamma = arg\min_\gamma <\gamma,M>_F + reg1\cdot\Omega(\gamma) + reg2\cdot f(\gamma)

        s.t. \gamma 1 = a

             \gamma^T 1= b

             \gamma\geq 0
    where :

    - M is the (ns,nt) metric cost matrix
    - :math:`\Omega` is the entropic regularization term :math:`\Omega(\gamma)=\sum_{i,j} \gamma_{i,j}\log(\gamma_{i,j})`
    - :math:`f` is the regularization term ( and df is its gradient)
    - a and b are source and target weights (sum to 1)

    The algorithm used for solving the problem is the generalized conditional gradient as discussed in  [5,7]_

    Parameters
    ----------
    a : np.ndarray (ns,)
        samples weights in the source domain
    b : np.ndarray (nt,)
        samples in the target domain
    M : np.ndarray (ns,nt)
        loss matrix
    reg1 : float
        Entropic Regularization term >0
    reg2 : float
        Second Regularization term >0
    G0 :  np.ndarray (ns,nt), optional
        initial guess (default is indep joint density)
    numItermax : int, optional
        Max number of iterations
    numInnerItermax : int, optional
        Max number of iterations of Sinkhorn
    stopThr : float, optional
        Stop threshol on error (>0)
    verbose : bool, optional
        Print information along iterations
    log : bool, optional
        record log if True

    Returns
    -------
    gamma : (ns x nt) ndarray
        Optimal transportation matrix for the given parameters
    log : dict
        log dictionary return only if log==True in parameters

    References
    ----------

    .. [5] N. Courty; R. Flamary; D. Tuia; A. Rakotomamonjy, "Optimal Transport for Domain Adaptation," in IEEE Transactions on Pattern Analysis and Machine Intelligence , vol.PP, no.99, pp.1-1
    .. [7] Rakotomamonjy, A., Flamary, R., & Courty, N. (2015). Generalized conditional gradient: analysis of convergence and applications. arXiv preprint arXiv:1510.06567.

    See Also
    --------
    ot.optim.cg : conditional gradient

    """

    loop = 1

    if log:
        log = {'loss': []}

    if G0 is None:
        G = np.outer(a, b)
    else:
        G = G0

    def cost(G):
        return np.sum(M * G) + reg1 * np.sum(G * np.log(G)) + reg2 * f(G)

    f_val = cost(G)
    if log:
        log['loss'].append(f_val)

    it = 0

    if verbose:
        print('{:5s}|{:12s}|{:8s}'.format(
            'It.', 'Loss', 'Delta loss') + '\n' + '-' * 32)
        print('{:5d}|{:8e}|{:8e}'.format(it, f_val, 0))

    while loop:

        it += 1
        old_fval = f_val

        # problem linearization
        Mi = M + reg2 * df(G)

        # solve linear program with Sinkhorn
        # Gc = sinkhorn_stabilized(a,b, Mi, reg1, numItermax = numInnerItermax)
        Gc = sinkhorn(a, b, Mi, reg1, numItermax=numInnerItermax)

        deltaG = Gc - G

        # line search
        dcost = Mi + reg1 * (1 + np.log(G))  # ??
        alpha, fc, f_val = line_search_armijo(cost, G, deltaG, dcost, f_val)

        G = G + alpha * deltaG

        # test convergence
        if it >= numItermax:
            loop = 0

        delta_fval = (f_val - old_fval) / abs(f_val)
        if abs(delta_fval) < stopThr:
            loop = 0

        if log:
            log['loss'].append(f_val)

        if verbose:
            if it % 20 == 0:
                print('{:5s}|{:12s}|{:8s}'.format(
                    'It.', 'Loss', 'Delta loss') + '\n' + '-' * 32)
            print('{:5d}|{:8e}|{:8e}'.format(it, f_val, delta_fval))

    if log:
        return G, log
    else:
        return G

def solve_1d_linesearch_quad_funct(a, b, c):
    """
    Solve on 0,1 the following problem:
    .. math::
        \min f(x)=a*x^{2}+b*x+c

    Parameters
    ----------
    a,b,c : float
            The coefficients of the quadratic function

    Returns
    -------
    x : float
        The optimal value which leads to the minimal cost

    """
    f0 = c
    df0 = b
    f1 = a + f0 + df0

    if a > 0:  # convex
        minimum = min(1, max(0, np.divide(-b, 2 * a)))
        return minimum
    else:  # non convex
        if f0 > f1:
            return 1
        else:
            return 0
<commit_msg><commit_after># -*- coding: utf-8 -*-
"""
Optimization algorithms for OT
"""

# Author: Remi Flamary <remi.flamary@unice.fr>
#         Titouan Vayer <titouan.vayer@irisa.fr>
# License: MIT License

import numpy as np
from scipy.optimize.linesearch import scalar_search_armijo
from .lp import emd
from .bregman import sinkhorn

# The corresponding scipy function does not work for matrices

def line_search_armijo(f, xk, pk, gfk, old_fval,
                       args=(), c1=1e-4, alpha0=0.99):
    """
    Armijo linesearch function that works with matrices

    find an approximate minimum of f(xk+alpha*pk) that satifies the
    armijo conditions.

    Parameters
    ----------

    f : function
        loss function
    xk : np.ndarray
        initial position
    pk : np.ndarray
        descent direction
    gfk : np.ndarray
        gradient of f at xk
    old_fval : float
        loss value at xk
    args : tuple, optional
        arguments given to f
    c1 : float, optional
        c1 const in armijo rule (>0)
    alpha0 : float, optional
        initial step (>0)

    Returns
    -------
    alpha : float
        step that satisfy armijo conditions
    fc : int
        nb of function call
    fa : float
        loss value at step alpha

    """
    xk = np.atleast_1d(xk)
    fc = [0]

    def phi(alpha1):
        fc[0] += 1
        return f(xk + alpha1 * pk, *args)

    if old_fval is None:
        phi0 = phi(0.)
    else:
        phi0 = old_fval

    derphi0 = np.sum(pk * gfk)  # Quickfix for matrices
    alpha, phi1 = scalar_search_armijo(
        phi, phi0, derphi0, c1=c1, alpha0=alpha0)

    return alpha, fc[0], phi1

def do_linesearch(cost, G, deltaG, Mi, f_val,
                  amijo=True, C1=None, C2=None, reg=None, Gc=None, constC=None, M=None):
    """
    Solve the linesearch in the FW iterations
    Parameters
    ----------
    cost : method
        The FGW cost
    G : ndarray, shape(ns,nt)
        The transport map at a given iteration of the FW
    deltaG : ndarray (ns,nt)
        Difference between the optimal map found by linearization in the FW algorithm and the value at a given iteration
    Mi : ndarray (ns,nt)
        Cost matrix of the linearized transport problem. Corresponds to the gradient of the cost
    f_val :  float
        Value of the cost at G
    amijo : bool, optionnal
            If True the steps of the line-search is found via an amijo research. Else closed form is used.
            If there is convergence issues use False.
    C1 : ndarray (ns,ns), optionnal
        Structure matrix in the source domain. Only used when amijo=False
    C2 : ndarray (nt,nt), optionnal
        Structure matrix in the target domain. Only used when amijo=False
    reg : float, optionnal
          Regularization parameter. Corresponds to the alpha parameter of FGW. Only used when amijo=False
    Gc : ndarray (ns,nt)
        Optimal map found by linearization in the FW algorithm. Only used when amijo=False
    constC : ndarray (ns,nt)
             Constant for the gromov cost. See [3]. Only used when amijo=False
    M : ndarray (ns,nt), optionnal
        Cost matrix between the features. Only used when amijo=False
    Returns
    -------
    alpha : float
            The optimal step size of the FW
    fc : int
         nb of function call. Useless here
    f_val :  float
             The value of the cost for the next iteration
    References
    ----------
    .. [24] Vayer Titouan, Chapel Laetitia, Flamary R{\'e}mi, Tavenard Romain
          and Courty Nicolas
        "Optimal Transport for structured data with application on graphs"
        International Conference on Machine Learning (ICML). 2019.
    """
    if amijo:
        alpha, fc, f_val = line_search_armijo(cost, G, deltaG, Mi, f_val)
    else:  # requires symetric matrices
        dot1 = np.dot(C1, deltaG)
        dot12 = dot1.dot(C2)
        a = -2 * reg * np.sum(dot12 * deltaG)
        b = np.sum((M + reg * constC) * deltaG) - 2 * reg * (np.sum(dot12 * G) + np.sum(np.dot(C1, G).dot(C2) * deltaG))
        c = cost(G)

        alpha = solve_1d_linesearch_quad_funct(a, b, c)
        fc = None
        f_val = cost(G + alpha * deltaG)

    return alpha, fc, f_val

def cg(a, b, M, reg, f, df, G0=None, numItermax=200,
       stopThr=1e-9, verbose=False, log=False, **kwargs):
    """
    Solve the general regularized OT problem with conditional gradient

        The function solves the following optimization problem:

    .. math::
        \gamma = arg\min_\gamma <\gamma,M>_F + reg*f(\gamma)

        s.t. \gamma 1 = a

             \gamma^T 1= b

             \gamma\geq 0
    where :

    - M is the (ns,nt) metric cost matrix
    - :math:`f` is the regularization term ( and df is its gradient)
    - a and b are source and target weights (sum to 1)

    The algorithm used for solving the problem is conditional gradient as discussed in  [1]_

    Parameters
    ----------
    a : np.ndarray (ns,)
        samples weights in the source domain
    b : np.ndarray (nt,)
        samples in the target domain
    M : np.ndarray (ns,nt)
        loss matrix
    reg : float
        Regularization term >0
    G0 :  np.ndarray (ns,nt), optional
        initial guess (default is indep joint density)
    numItermax : int, optional
        Max number of iterations
    stopThr : float, optional
        Stop threshol on error (>0)
    verbose : bool, optional
        Print information along iterations
    log : bool, optional
        record log if True
    kwargs : dict
             Parameters for linesearch

    Returns
    -------
    gamma : (ns x nt) ndarray
        Optimal transportation matrix for the given parameters
    log : dict
        log dictionary return only if log==True in parameters

    References
    ----------

    .. [1] Ferradans, S., Papadakis, N., Peyré, G., & Aujol, J. F. (2014). Regularized discrete optimal transport. SIAM Journal on Imaging Sciences, 7(3), 1853-1882.

    See Also
    --------
    ot.lp.emd : Unregularized optimal ransport
    ot.bregman.sinkhorn : Entropic regularized optimal transport

    """

    loop = 1

    if log:
        log = {'loss': []}

    if G0 is None:
        G = np.outer(a, b)
    else:
        G = G0

    def cost(G):
        return np.sum(M * G) + reg * f(G)

    f_val = cost(G)
    if log:
        log['loss'].append(f_val)

    it = 0

    if verbose:
        print('{:5s}|{:12s}|{:8s}'.format(
            'It.', 'Loss', 'Delta loss') + '\n' + '-' * 32)
        print('{:5d}|{:8e}|{:8e}'.format(it, f_val, 0))

    while loop:

        it += 1
        old_fval = f_val

        # problem linearization
        Mi = M + reg * df(G)
        # set M positive
        Mi += Mi.min()

        # solve linear program
        Gc = emd(a, b, Mi)

        deltaG = Gc - G

        # line search
        alpha, fc, f_val = do_linesearch(cost, G, deltaG, Mi, f_val, reg=reg, M=M, Gc=Gc, **kwargs)

        G = G + alpha * deltaG

        # test convergence
        if it >= numItermax:
            loop = 0

        delta_fval = (f_val - old_fval) / abs(f_val)
        if abs(delta_fval) < stopThr:
            loop = 0

        if log:
            log['loss'].append(f_val)

        if verbose:
            if it % 20 == 0:
                print('{:5s}|{:12s}|{:8s}'.format(
                    'It.', 'Loss', 'Delta loss') + '\n' + '-' * 32)
            print('{:5d}|{:8e}|{:8e}'.format(it, f_val, delta_fval))

    if log:
        return G, log
    else:
        return G

def gcg(a, b, M, reg1, reg2, f, df, G0=None, numItermax=10,
        numInnerItermax=200, stopThr=1e-9, verbose=False, log=False):
    """
    Solve the general regularized OT problem with the generalized conditional gradient

        The function solves the following optimization problem:

    .. math::
        \gamma = arg\min_\gamma <\gamma,M>_F + reg1\cdot\Omega(\gamma) + reg2\cdot f(\gamma)

        s.t. \gamma 1 = a

             \gamma^T 1= b

             \gamma\geq 0
    where :

    - M is the (ns,nt) metric cost matrix
    - :math:`\Omega` is the entropic regularization term :math:`\Omega(\gamma)=\sum_{i,j} \gamma_{i,j}\log(\gamma_{i,j})`
    - :math:`f` is the regularization term ( and df is its gradient)
    - a and b are source and target weights (sum to 1)

    The algorithm used for solving the problem is the generalized conditional gradient as discussed in  [5,7]_

    Parameters
    ----------
    a : np.ndarray (ns,)
        samples weights in the source domain
    b : np.ndarray (nt,)
        samples in the target domain
    M : np.ndarray (ns,nt)
        loss matrix
    reg1 : float
        Entropic Regularization term >0
    reg2 : float
        Second Regularization term >0
    G0 :  np.ndarray (ns,nt), optional
        initial guess (default is indep joint density)
    numItermax : int, optional
        Max number of iterations
    numInnerItermax : int, optional
        Max number of iterations of Sinkhorn
    stopThr : float, optional
        Stop threshol on error (>0)
    verbose : bool, optional
        Print information along iterations
    log : bool, optional
        record log if True

    Returns
    -------
    gamma : (ns x nt) ndarray
        Optimal transportation matrix for the given parameters
    log : dict
        log dictionary return only if log==True in parameters

    References
    ----------

    .. [5] N. Courty; R. Flamary; D. Tuia; A. Rakotomamonjy, "Optimal Transport for Domain Adaptation," in IEEE Transactions on Pattern Analysis and Machine Intelligence , vol.PP, no.99, pp.1-1
    .. [7] Rakotomamonjy, A., Flamary, R., & Courty, N. (2015). Generalized conditional gradient: analysis of convergence and applications. arXiv preprint arXiv:1510.06567.

    See Also
    --------
    ot.optim.cg : conditional gradient

    """

    loop = 1

    if log:
        log = {'loss': []}

    if G0 is None:
        G = np.outer(a, b)
    else:
        G = G0

    def cost(G):
        return np.sum(M * G) + reg1 * np.sum(G * np.log(G)) + reg2 * f(G)

    f_val = cost(G)
    if log:
        log['loss'].append(f_val)

    it = 0

    if verbose:
        print('{:5s}|{:12s}|{:8s}'.format(
            'It.', 'Loss', 'Delta loss') + '\n' + '-' * 32)
        print('{:5d}|{:8e}|{:8e}'.format(it, f_val, 0))

    while loop:

        it += 1
        old_fval = f_val

        # problem linearization
        Mi = M + reg2 * df(G)

        # solve linear program with Sinkhorn
        # Gc = sinkhorn_stabilized(a,b, Mi, reg1, numItermax = numInnerItermax)
        Gc = sinkhorn(a, b, Mi, reg1, numItermax=numInnerItermax)

        deltaG = Gc - G

        # line search
        dcost = Mi + reg1 * (1 + np.log(G))  # ??
        alpha, fc, f_val = line_search_armijo(cost, G, deltaG, dcost, f_val)

        G = G + alpha * deltaG

        # test convergence
        if it >= numItermax:
            loop = 0

        delta_fval = (f_val - old_fval) / abs(f_val)
        if abs(delta_fval) < stopThr:
            loop = 0

        if log:
            log['loss'].append(f_val)

        if verbose:
            if it % 20 == 0:
                print('{:5s}|{:12s}|{:8s}'.format(
                    'It.', 'Loss', 'Delta loss') + '\n' + '-' * 32)
            print('{:5d}|{:8e}|{:8e}'.format(it, f_val, delta_fval))

    if log:
        return G, log
    else:
        return G

def solve_1d_linesearch_quad_funct(a, b, c):
    """
    Solve on 0,1 the following problem:
    .. math::
        \min f(x)=a*x^{2}+b*x+c

    Parameters
    ----------
    a,b,c : float
            The coefficients of the quadratic function

    Returns
    -------
    x : float
        The optimal value which leads to the minimal cost

    """
    f0 = c
    df0 = b
    f1 = a + f0 + df0

    if a > 0:  # convex
        minimum = min(1, max(0, np.divide(-b, 2.0 * a)))
        return minimum
    else:  # non convex
        if f0 > f1:
            return 1
        else:
            return 0
<|endoftext|>


<commit_before>class Instance:
    """Create a new Instance instance.

    It may take as parameter either:
      - a string
      - a list of strings as first parameters
      - the parameters given as the constructor parameters (must be strings)
    """
    def __new__(cls, *p):
        if p and p[0] == 0:
            return None
        elif p and isinstance(p[0], (int, long)):
            # instance creation from ctypes
            o=object.__new__(cls)
            o._as_parameter_=ctypes.c_void_p(p[0])
            return o
        elif len(p) == 1 and isinstance(p[0], basestring):
            # Only 1 string parameter: should be a parameter line
            p=p[0].split(' ')
        elif len(p) == 1 and isinstance(p[0], (tuple, list)):
            p=p[0]

        if not p and detected_plugin_path is not None:
            # No parameters passed. Under win32 and MacOS, specify
            # the detected_plugin_path if present.
            p=[ 'vlc', '--plugin-path='+ detected_plugin_path ]
        return libvlc_new(len(p), p)

    def media_player_new(self, uri=None):
        """Create a new MediaPlayer instance.

        @param uri: an optional URI to play in the player.
        """
        p=libvlc_media_player_new(self)
        if uri:
            p.set_media(self.media_new(uri))
        p._instance=self
        return p

    def media_list_player_new(self):
        """Create a new MediaListPlayer instance.
        """
        p=libvlc_media_list_player_new(self)
        p._instance=self
        return p

    def media_new(self, mrl, *options):
        """Create a new Media instance.

        Options can be specified as supplementary string parameters, e.g.
        m=i.media_new('foo.avi', 'sub-filter=marq{marquee=Hello}', 'vout-filter=invert')
        """
        m=libvlc_media_new_location(self, mrl)
        for o in options:
            libvlc_media_add_option(m, o)
        return m

    def audio_output_enumerate_devices(self):
        """Enumerate the defined audio output devices.

        The result is a list of dict (name, description)
        """
        l = []
        head = ao = libvlc_audio_output_list_get(self)
        while ao:
            l.append( { 'name': ao.contents.name,
                        'description': ao.contents.description,
                        'devices': [ { 'id': libvlc_audio_output_device_id(self, ao.contents.name, i),
                                       'longname': libvlc_audio_output_device_longname(self, ao.contents.name, i) }
                                     for i in range(libvlc_audio_output_device_count(self, ao.contents.name) ) ] } )
            ao = ao.contents.next
        libvlc_audio_output_list_release(head)
        return l

class Media:
    """Create a new Media instance.
    """

    def add_options(self, *list_of_options):
        """Add a list of options to the media.

        Options must be written without the double-dash, e.g.:
        m.add_options('sub-filter=marq@test{marquee=Hello}', 'video-filter=invert')

        Note that you also can directly pass these options in the Instance.media_new method:
        m=instance.media_new( 'foo.avi', 'sub-filter=marq@test{marquee=Hello}', 'video-filter=invert')
        """
        for o in list_of_options:
            self.add_option(o)

class MediaPlayer:
    """Create a new MediaPlayer instance.

    It may take as parameter either:
      - a string (media URI). In this case, a vlc.Instance will be created.
      - a vlc.Instance
    """
    def __new__(cls, *p):
        if p and p[0] == 0:
            return None
        elif p and isinstance(p[0], (int, long)):
            # instance creation from ctypes
            o=object.__new__(cls)
            o._as_parameter_=ctypes.c_void_p(p[0])
            return o

        if p and isinstance(p[0], Instance):
            return p[0].media_player_new()
        else:
            i=Instance()
            o=i.media_player_new()
            if p:
                o.set_media(i.media_new(p[0]))
            return o

    def get_instance(self):
        """Return the associated vlc.Instance.
        """
        return self._instance

    def set_mrl(self, mrl, *options):
        """Set the MRL to play.

        @param mrl: The MRL
        @param options: a list of options
        @return The Media object
        """
        m = self.get_instance().media_new(mrl, *options)
        self.set_media(m)
        return m

    def video_get_spu_description(self):
        """Get the description of available video subtitles.
        """
        return track_description_list(libvlc_video_get_spu_description(self))

    def video_get_title_description(self):
        """Get the description of available titles.
        """
        return track_description_list(libvlc_video_get_title_description(self))

    def video_get_chapter_description(self, title):
        """Get the description of available chapters for specific title.
        @param i_title selected title (int)
        """
        return track_description_list(libvlc_video_get_chapter_description(self, title))

    def video_get_track_description(self):
        """Get the description of available video tracks.
        """
        return track_description_list(libvlc_video_get_track_description(self))

    def audio_get_track_description(self):
        """Get the description of available audio tracks.
        """
        return track_description_list(libvlc_audio_get_track_description(self))

class MediaListPlayer:
    """Create a new MediaListPlayer instance.

    It may take as parameter either:
      - a vlc.Instance
      - nothing
    """
    def __new__(cls, *p):
        if p and p[0] == 0:
            return None
        elif p and isinstance(p[0], (int, long)):
            # instance creation from ctypes
            o=object.__new__(cls)
            o._as_parameter_=ctypes.c_void_p(p[0])
            return o
        elif len(p) == 1 and isinstance(p[0], (tuple, list)):
            p=p[0]

        if p and isinstance(p[0], Instance):
            return p[0].media_list_player_new()
        else:
            i=Instance()
            o=i.media_list_player_new()
            return o

    def get_instance(self):
        """Return the associated vlc.Instance.
        """
        return self._instance

class LogIterator:
    """Create a new VLC log iterator.
    """
    def __iter__(self):
        return self

    def next(self):
        if not self.has_next():
            raise StopIteration
        buf=LogMessage()
        ret=libvlc_log_iterator_next(self, buf)
        return ret.contents

class Log:
    """Create a new VLC log instance.
    """
    def __iter__(self):
        return self.get_iterator()

    def dump(self):
        return [ str(m) for m in self ]

class EventManager:
    """Create an event manager and handler.

       This class interposes the registration and handling of
       event notifications in order to (a) allow any number of
       positional and/or keyword arguments to the callback (in
       addition to the Event instance), (b) preserve the Python
       argument objects and (c) remove the need for decorating
       each callback with decorator '@callbackmethod'.

       Calls from ctypes to Python callbacks are handled by
       function _callback_handler.

       A side benefit of this scheme is that the callback and
       all argument objects remain alive (i.e. are not garbage
       collected) until *after* the event notification has
       been unregistered.

       NOTE: only a single notification can be registered for
       each event type in an EventManager instance.
    """
    def __new__(cls, ptr=None):
        if ptr is None:
            raise LibVLCException("(INTERNAL) ctypes class.")
        if ptr == 0:
            return None
        o = object.__new__(cls)
        o._as_parameter_ = ptr  # was ctypes.c_void_p(ptr)
        o._callbacks_ = {}  # 3-tuples of Python objs
        o._callback_handler = None
        return o

    def event_attach(self, eventtype, callback, *args, **kwds):
        """Register an event notification.

        @param eventtype: the desired event type to be notified about
        @param callback: the function to call when the event occurs
        @param args: optional positional arguments for the callback
        @param kwds: optional keyword arguments for the callback
        @return: 0 on success, ENOMEM on error

        NOTE: The callback must have at least one argument, the Event
        instance.  The optional positional and keyword arguments are
        in addition to the first one.
        """
        if not isinstance(eventtype, EventType):
            raise LibVLCException("%s required: %r" % ('EventType', eventtype))
        if not hasattr(callback, '__call__'):  # callable()
            raise LibVLCException("%s required: %r" % ('callable', callback))

        if self._callback_handler is None:
            _called_from_ctypes = ctypes.CFUNCTYPE(None, ctypes.POINTER(Event), ctypes.c_void_p)
            @_called_from_ctypes
            def _callback_handler(event, data):
                """(INTERNAL) handle callback call from ctypes.

                Note: we cannot simply make this an instance method of
                EventManager since ctypes callback does not append
                self as first parameter. Hence we use a closure.
                """
                try: # retrieve Python callback and arguments
                    call, args, kwds = self._callbacks_[event.contents.type.value]
                    # We dereference event.contents here to simplify callback code.
                    call(event.contents, *args, **kwds)
                except KeyError:  # detached?
                    pass
            self._callback_handler = _callback_handler

        r = libvlc_event_attach(self, eventtype, self._callback_handler, None)
        if not r:
            self._callbacks_[eventtype.value] = (callback, args, kwds)
        return r

    def event_detach(self, eventtype):
        """Unregister an event notification.

        @param eventtype: the event type notification to be removed
        """
        if not isinstance(eventtype, EventType):
            raise LibVLCException("%s required: %r" % ('EventType', eventtype))

        t = eventtype.value
        if t in self._callbacks_:
            del self._callbacks_[t] # remove, regardless of libvlc return value
            libvlc_event_detach(self, eventtype, self._callback_handler, None)
<commit_msg>python-vlc: implement MediaPlayer.video_get_(size|width|height|cursor)<commit_after>class Instance:
    """Create a new Instance instance.

    It may take as parameter either:
      - a string
      - a list of strings as first parameters
      - the parameters given as the constructor parameters (must be strings)
    """
    def __new__(cls, *p):
        if p and p[0] == 0:
            return None
        elif p and isinstance(p[0], (int, long)):
            # instance creation from ctypes
            o=object.__new__(cls)
            o._as_parameter_=ctypes.c_void_p(p[0])
            return o
        elif len(p) == 1 and isinstance(p[0], basestring):
            # Only 1 string parameter: should be a parameter line
            p=p[0].split(' ')
        elif len(p) == 1 and isinstance(p[0], (tuple, list)):
            p=p[0]

        if not p and detected_plugin_path is not None:
            # No parameters passed. Under win32 and MacOS, specify
            # the detected_plugin_path if present.
            p=[ 'vlc', '--plugin-path='+ detected_plugin_path ]
        return libvlc_new(len(p), p)

    def media_player_new(self, uri=None):
        """Create a new MediaPlayer instance.

        @param uri: an optional URI to play in the player.
        """
        p=libvlc_media_player_new(self)
        if uri:
            p.set_media(self.media_new(uri))
        p._instance=self
        return p

    def media_list_player_new(self):
        """Create a new MediaListPlayer instance.
        """
        p=libvlc_media_list_player_new(self)
        p._instance=self
        return p

    def media_new(self, mrl, *options):
        """Create a new Media instance.

        Options can be specified as supplementary string parameters, e.g.
        m=i.media_new('foo.avi', 'sub-filter=marq{marquee=Hello}', 'vout-filter=invert')
        """
        m=libvlc_media_new_location(self, mrl)
        for o in options:
            libvlc_media_add_option(m, o)
        return m

    def audio_output_enumerate_devices(self):
        """Enumerate the defined audio output devices.

        The result is a list of dict (name, description)
        """
        l = []
        head = ao = libvlc_audio_output_list_get(self)
        while ao:
            l.append( { 'name': ao.contents.name,
                        'description': ao.contents.description,
                        'devices': [ { 'id': libvlc_audio_output_device_id(self, ao.contents.name, i),
                                       'longname': libvlc_audio_output_device_longname(self, ao.contents.name, i) }
                                     for i in range(libvlc_audio_output_device_count(self, ao.contents.name) ) ] } )
            ao = ao.contents.next
        libvlc_audio_output_list_release(head)
        return l

class Media:
    """Create a new Media instance.
    """

    def add_options(self, *list_of_options):
        """Add a list of options to the media.

        Options must be written without the double-dash, e.g.:
        m.add_options('sub-filter=marq@test{marquee=Hello}', 'video-filter=invert')

        Note that you also can directly pass these options in the Instance.media_new method:
        m=instance.media_new( 'foo.avi', 'sub-filter=marq@test{marquee=Hello}', 'video-filter=invert')
        """
        for o in list_of_options:
            self.add_option(o)

class MediaPlayer:
    """Create a new MediaPlayer instance.

    It may take as parameter either:
      - a string (media URI). In this case, a vlc.Instance will be created.
      - a vlc.Instance
    """
    def __new__(cls, *p):
        if p and p[0] == 0:
            return None
        elif p and isinstance(p[0], (int, long)):
            # instance creation from ctypes
            o=object.__new__(cls)
            o._as_parameter_=ctypes.c_void_p(p[0])
            return o

        if p and isinstance(p[0], Instance):
            return p[0].media_player_new()
        else:
            i=Instance()
            o=i.media_player_new()
            if p:
                o.set_media(i.media_new(p[0]))
            return o

    def get_instance(self):
        """Return the associated vlc.Instance.
        """
        return self._instance

    def set_mrl(self, mrl, *options):
        """Set the MRL to play.

        @param mrl: The MRL
        @param options: a list of options
        @return The Media object
        """
        m = self.get_instance().media_new(mrl, *options)
        self.set_media(m)
        return m

    def video_get_spu_description(self):
        """Get the description of available video subtitles.
        """
        return track_description_list(libvlc_video_get_spu_description(self))

    def video_get_title_description(self):
        """Get the description of available titles.
        """
        return track_description_list(libvlc_video_get_title_description(self))

    def video_get_chapter_description(self, title):
        """Get the description of available chapters for specific title.
        @param i_title selected title (int)
        """
        return track_description_list(libvlc_video_get_chapter_description(self, title))

    def video_get_track_description(self):
        """Get the description of available video tracks.
        """
        return track_description_list(libvlc_video_get_track_description(self))

    def audio_get_track_description(self):
        """Get the description of available audio tracks.
        """
        return track_description_list(libvlc_audio_get_track_description(self))

    def video_get_size(self, num=0):
        """Get the size of a video in pixels as 2-tuple (width, height).

        @param num: video number (default 0)
        """
        x, y = ctypes.c_ulong(), ctypes.c_ulong()  # or c_uint?
        if libvlc_video_get_size(self, num, ctypes.byref(x), ctypes.byref(y)):
            raise LibVLCException('invalid video number (%s)' % (num,))
        return int(x.value), int(y.value)

    def video_get_width(self, num=0):
        """Get the width of a video in pixels.

        @param num: video number (default 0)
        """
        return self.video_get_size(num)[0]

    def video_get_height(self, num=0):
        """Get the height of a video in pixels.

        @param num: video number (default 0)
        """
        return self.video_get_size(num)[1]

    def video_get_cursor(self, num=0):
        """Get the mouse pointer coordinates over a video as 2-tuple (x, y).

        Coordinates are expressed in terms of the decoded video resolution,
        <b>not</b> in terms of pixels on the screen/viewport.  To get the
        latter, you must query your windowing system directly.

        Either coordinate may be negative or larger than the corresponding
        size of the video, if the cursor is outside the rendering area.

        @warning The coordinates may be out-of-date if the pointer is not
        located on the video rendering area.  LibVLC does not track the
        mouse pointer if it is outside the video widget.

        @note LibVLC does not support multiple mouse pointers (but does
        support multiple input devices sharing the same pointer).

        @param num: video number (default 0)
        """
        x, y = ctypes.c_long(), ctypes.c_long()  # or c_int?
        if libvlc_video_get_cursor(self, num, ctypes.byref(x), ctypes.byref(y)):
            raise LibVLCException('invalid video number (%s)' % (num,))
        return int(x.value), int(y.value)

class MediaListPlayer:
    """Create a new MediaListPlayer instance.

    It may take as parameter either:
      - a vlc.Instance
      - nothing
    """
    def __new__(cls, *p):
        if p and p[0] == 0:
            return None
        elif p and isinstance(p[0], (int, long)):
            # instance creation from ctypes
            o=object.__new__(cls)
            o._as_parameter_=ctypes.c_void_p(p[0])
            return o
        elif len(p) == 1 and isinstance(p[0], (tuple, list)):
            p=p[0]

        if p and isinstance(p[0], Instance):
            return p[0].media_list_player_new()
        else:
            i=Instance()
            o=i.media_list_player_new()
            return o

    def get_instance(self):
        """Return the associated vlc.Instance.
        """
        return self._instance

class LogIterator:
    """Create a new VLC log iterator.
    """
    def __iter__(self):
        return self

    def next(self):
        if not self.has_next():
            raise StopIteration
        buf=LogMessage()
        ret=libvlc_log_iterator_next(self, buf)
        return ret.contents

class Log:
    """Create a new VLC log instance.
    """
    def __iter__(self):
        return self.get_iterator()

    def dump(self):
        return [ str(m) for m in self ]

class EventManager:
    """Create an event manager and handler.

       This class interposes the registration and handling of
       event notifications in order to (a) allow any number of
       positional and/or keyword arguments to the callback (in
       addition to the Event instance), (b) preserve the Python
       argument objects and (c) remove the need for decorating
       each callback with decorator '@callbackmethod'.

       Calls from ctypes to Python callbacks are handled by
       function _callback_handler.

       A side benefit of this scheme is that the callback and
       all argument objects remain alive (i.e. are not garbage
       collected) until *after* the event notification has
       been unregistered.

       NOTE: only a single notification can be registered for
       each event type in an EventManager instance.
    """
    def __new__(cls, ptr=None):
        if ptr is None:
            raise LibVLCException("(INTERNAL) ctypes class.")
        if ptr == 0:
            return None
        o = object.__new__(cls)
        o._as_parameter_ = ptr  # was ctypes.c_void_p(ptr)
        o._callbacks_ = {}  # 3-tuples of Python objs
        o._callback_handler = None
        return o

    def event_attach(self, eventtype, callback, *args, **kwds):
        """Register an event notification.

        @param eventtype: the desired event type to be notified about
        @param callback: the function to call when the event occurs
        @param args: optional positional arguments for the callback
        @param kwds: optional keyword arguments for the callback
        @return: 0 on success, ENOMEM on error

        NOTE: The callback must have at least one argument, the Event
        instance.  The optional positional and keyword arguments are
        in addition to the first one.
        """
        if not isinstance(eventtype, EventType):
            raise LibVLCException("%s required: %r" % ('EventType', eventtype))
        if not hasattr(callback, '__call__'):  # callable()
            raise LibVLCException("%s required: %r" % ('callable', callback))

        if self._callback_handler is None:
            _called_from_ctypes = ctypes.CFUNCTYPE(None, ctypes.POINTER(Event), ctypes.c_void_p)
            @_called_from_ctypes
            def _callback_handler(event, data):
                """(INTERNAL) handle callback call from ctypes.

                Note: we cannot simply make this an instance method of
                EventManager since ctypes callback does not append
                self as first parameter. Hence we use a closure.
                """
                try: # retrieve Python callback and arguments
                    call, args, kwds = self._callbacks_[event.contents.type.value]
                    # We dereference event.contents here to simplify callback code.
                    call(event.contents, *args, **kwds)
                except KeyError:  # detached?
                    pass
            self._callback_handler = _callback_handler

        r = libvlc_event_attach(self, eventtype, self._callback_handler, None)
        if not r:
            self._callbacks_[eventtype.value] = (callback, args, kwds)
        return r

    def event_detach(self, eventtype):
        """Unregister an event notification.

        @param eventtype: the event type notification to be removed
        """
        if not isinstance(eventtype, EventType):
            raise LibVLCException("%s required: %r" % ('EventType', eventtype))

        t = eventtype.value
        if t in self._callbacks_:
            del self._callbacks_[t] # remove, regardless of libvlc return value
            libvlc_event_detach(self, eventtype, self._callback_handler, None)
<|endoftext|>


<commit_before># -*- coding: UTF-8 -*-
from django import http
from django.conf import settings
from django.contrib import auth
from django.contrib.auth.decorators import login_required
from django.core.mail import send_mail
from django.core.urlresolvers import reverse
from django.db import transaction
from django.shortcuts import get_object_or_404, render_to_response
from django.template import RequestContext
from django.template.loader import render_to_string

from assopy.models import User, UserIdentity
from assopy.views import render_to, HttpResponseRedirectSeeOther

import forms
import models
from conference.models import Ticket

import logging
import uuid

log = logging.getLogger('p3.views')

def map_js(request):
    return render_to_response(
        'p3/map.js', {}, context_instance=RequestContext(request), mimetype = 'text/javascript')

@login_required
@render_to('p3/tickets.html')
def tickets(request):
    tickets = models.TicketConference.objects.available(request.user, settings.CONFERENCE_CONFERENCE)
    return {
        'tickets': tickets,
    }

def _assign_ticket(ticket, email):
    try:
        recipient = auth.models.User.objects.get(email=email)
    except auth.models.User.DoesNotExist:
        try:
            # qui uso filter + [0] invece che .get perchè potrebbe accadere,
            # anche se non dovrebbe, che due identità abbiano la stessa email
            # (ad esempio se una persona a usato la stessa mail su più servizi
            # remoti ma ha collegato questi servizi a due utenti locali
            # diversi). Non è un problema se più identità hanno la stessa email
            # (nota che il backend di autenticazione già verifica che la stessa
            # email non venga usata due volte per creare utenti django) perché
            # in ogni caso si tratta di email verificate da servizi esterni.
            recipient = UserIdentity.objects.filter(email=email)[0].user.user
        except IndexError:
            recipient = None
    if recipient is None:
        log.info('No user found for the email "%s"; time to create a new one', email)
        u = User.objects.create_user(email=email, token=True, send_mail=False)
        recipient = u.user
        name = email
    else:
        log.info('Found a local user (%s) for the email "%s"', recipient, email)
        if not recipient.assopy_user.token:
            recipient.assopy_user.token = str(uuid.uuid4())
            recipient.assopy_user.save()
        name = recipient.assopy_user.name()
    ctx = {
        'name': name,
        'ticket': ticket,
        'conference': 'Europython 2011',
        'link': settings.DEFAULT_URL_PREFIX + reverse('p3-user', kwargs={'token': recipient.assopy_user.token}),
    }
    body = render_to_string('p3/emails/ticket_assigned.txt', ctx)
    send_mail('Ticket assigned to you', body, 'info@pycon.it', [email])

@login_required
@transaction.commit_on_success
def ticket(request, tid):
    t = get_object_or_404(Ticket, pk=tid)
    try:
        p3c = t.p3_conference
    except models.TicketConference.DoesNotExist:
        p3c = None
        assigned_to = None
    else:
        assigned_to = p3c.assigned_to
    if t.user != request.user:
        if assigned_to is None or assigned_to != request.user.email:
            raise http.Http404()
    if request.method == 'POST':
        form = forms.FormTicket(instance=p3c, data=request.POST, prefix='t%d' % (t.id,))
        if not form.is_valid():
            return http.HttpResponseBadRequest()
        data = form.cleaned_data
        t.name = data['ticket_name']
        t.save()
        x = form.save(commit=False)
        x.ticket = t
        if assigned_to != x.assigned_to:
            if x.assigned_to:
                log.info('ticket assigned to "%s"', x.assigned_to)
                _assign_ticket(t, x.assigned_to)
            else:
                log.info('ticket reclaimed (previously assigned to "%s")', assigned_to)
        x.save()
    if request.is_ajax():
        # piccolo aiuto per le chiamate ajax che non sono interessate alla
        # risposta
        return http.HttpResponse('')
    else:
        return HttpResponseRedirectSeeOther(reverse('p3-tickets'))

def user(request, token):
    """
    view che logga automaticamente un utente (se il token è valido) e lo
    ridirige alla pagine dei tickets
    """
    u = get_object_or_404(User, token=token)
    if not u.verified:
        u.verified = True
        u.save()
    user = auth.authenticate(uid=u.user.id)
    auth.login(request, user)
    return HttpResponseRedirectSeeOther(reverse('p3-tickets'))
<commit_msg>mi assicuro che solo il proprietario del biglietto possa assegnarlo (inoltre copio il nome del biglietto per gli utenti anonimi)<commit_after># -*- coding: UTF-8 -*-
from django import http
from django.conf import settings
from django.contrib import auth
from django.contrib.auth.decorators import login_required
from django.core.mail import send_mail
from django.core.urlresolvers import reverse
from django.db import transaction
from django.shortcuts import get_object_or_404, render_to_response
from django.template import RequestContext
from django.template.loader import render_to_string

from assopy.models import User, UserIdentity
from assopy.views import render_to, HttpResponseRedirectSeeOther

import forms
import models
from conference.models import Ticket

import logging
import uuid

log = logging.getLogger('p3.views')

def map_js(request):
    return render_to_response(
        'p3/map.js', {}, context_instance=RequestContext(request), mimetype = 'text/javascript')

@login_required
@render_to('p3/tickets.html')
def tickets(request):
    tickets = models.TicketConference.objects.available(request.user, settings.CONFERENCE_CONFERENCE)
    return {
        'tickets': tickets,
    }

def _assign_ticket(ticket, email):
    try:
        recipient = auth.models.User.objects.get(email=email)
    except auth.models.User.DoesNotExist:
        try:
            # qui uso filter + [0] invece che .get perchè potrebbe accadere,
            # anche se non dovrebbe, che due identità abbiano la stessa email
            # (ad esempio se una persona a usato la stessa mail su più servizi
            # remoti ma ha collegato questi servizi a due utenti locali
            # diversi). Non è un problema se più identità hanno la stessa email
            # (nota che il backend di autenticazione già verifica che la stessa
            # email non venga usata due volte per creare utenti django) perché
            # in ogni caso si tratta di email verificate da servizi esterni.
            recipient = UserIdentity.objects.filter(email=email)[0].user.user
        except IndexError:
            recipient = None
    if recipient is None:
        log.info('No user found for the email "%s"; time to create a new one', email)
        u = User.objects.create_user(email=email, token=True, send_mail=False)
        recipient = u.user
        name = email
    else:
        log.info('Found a local user (%s) for the email "%s"', recipient, email)
        if not recipient.assopy_user.token:
            recipient.assopy_user.token = str(uuid.uuid4())
            recipient.assopy_user.save()
        name = recipient.assopy_user.name()
    ctx = {
        'name': name,
        'ticket': ticket,
        'conference': 'Europython 2011',
        'link': settings.DEFAULT_URL_PREFIX + reverse('p3-user', kwargs={'token': recipient.assopy_user.token}),
    }
    body = render_to_string('p3/emails/ticket_assigned.txt', ctx)
    send_mail('Ticket assigned to you', body, 'info@pycon.it', [email])

@login_required
@transaction.commit_on_success
def ticket(request, tid):
    t = get_object_or_404(Ticket, pk=tid)
    try:
        p3c = t.p3_conference
    except models.TicketConference.DoesNotExist:
        p3c = None
        assigned_to = None
    else:
        assigned_to = p3c.assigned_to
    if t.user != request.user:
        if assigned_to is None or assigned_to != request.user.email:
            raise http.Http404()
    if request.method == 'POST':
        form = forms.FormTicket(instance=p3c, data=request.POST, prefix='t%d' % (t.id,))
        if not form.is_valid():
            return http.HttpResponseBadRequest()
        data = form.cleaned_data
        t.name = data['ticket_name']
        t.save()
        x = form.save(commit=False)
        x.ticket = t
        if t.user != request.user:
            # solo il proprietario del biglietto può riassegnarlo
            x.assigned_to = assigned_to
        x.save()
        if t.user == request.user and assigned_to != x.assigned_to:
            if x.assigned_to:
                log.info('ticket assigned to "%s"', x.assigned_to)
                _assign_ticket(t, x.assigned_to)
            else:
                log.info('ticket reclaimed (previously assigned to "%s")', assigned_to)
        if t.user != request.user and not request.user.first_name and not request.user.last_name and data['ticket_name']:
            # shortcut, l'utente non ha impostati né il nome né il cognome (e
            # tra l'altro non è la persona che ha comprato il biglietto) per
            # dare un nome al suo profilo copio le informazioni che ha dato nel
            # suo utente
            try:
                f, l = data['ticket_name'].strip().split(' ', 1)
            except ValueError:
                f = data['ticket_name'].strip()
                l = ''
            request.user.assopy_user.setBilling(firstname=f, lastname=l)

    if request.is_ajax():
        # piccolo aiuto per le chiamate ajax che non sono interessate alla
        # risposta
        return http.HttpResponse('')
    else:
        return HttpResponseRedirectSeeOther(reverse('p3-tickets'))

def user(request, token):
    """
    view che logga automaticamente un utente (se il token è valido) e lo
    ridirige alla pagine dei tickets
    """
    u = get_object_or_404(User, token=token)
    if not u.verified:
        u.verified = True
        u.save()
    user = auth.authenticate(uid=u.user.id)
    auth.login(request, user)
    return HttpResponseRedirectSeeOther(reverse('p3-tickets'))
<|endoftext|>


<commit_before>import json, random, urllib2

def declare():
    return {"reddit": "privmsg"}

def callback(self, type, isop, command="", msg="", user="", channel="", mode=""):

    try:
        u = str(msg.split(' ', 1)[1])
    except:
        self.msg(channel, "Please specify a subreddit!")
        return

    try:

        req = urllib2.Request("https://www.reddit.com/r/" + u + "/new.json", headers={ 'User-Agent': 'UNIX:the_kgb:0.157 http://github.com/stqism/THE_KGB' })
        fd = urllib2.urlopen(req)
        reddit_api = json.loads(fd.read())
        fd.close()

        cringe = []

        for i in reddit_api['data']['children']:
            url = i['data']['url']
            title = i['data']['title']
            selfpost = bool(i['data']['is_self'])
            post = "https://reddit.com" + i['data']['permalink']

            if 'imgur' in url:

                if 'http://i.imgur.com' in url:  #force https
                    url = 'https://i.imgur.com/%s' % (url.split('/')[3])

                if 'http://' in url and '/a/' not in url:   #direct URLs
                    if 'gallery' in url:
                        url = 'https://i.imgur.com/%s.jpg' % (url.split('/')[4])
                    else:
                        url = 'https://i.imgur.com/%s.jpg' % (url.split('/')[3])

            cringe.append([title, url, post])

        item = random.choice(cringe)

        if not selfpost:
            via = "     (via: " + item[2] + ")"
            self.msg(channel, str(item[0] + " " + item[1] + via))
        else:
            self.msg(channel, str(item[0] + " " + item[1]))

    except Exception, e:
        self.msg('#the_kgb', str(e))

<commit_msg>reddit module unit testing<commit_after>import json, random, urllib2

def declare():
    return {"reddit": "privmsg"}

def callback(self, type, isop, command="", msg="", user="", channel="", mode=""):

    try:
        u = str(msg.split(' ', 1)[1])
    except:
        return self.msg(channel, "Please specify a subreddit!")

    try:

        req = urllib2.Request("https://www.reddit.com/r/" + u + "/new.json", headers={ 'User-Agent': 'UNIX:the_kgb:0.157 http://github.com/stqism/THE_KGB' })
        fd = urllib2.urlopen(req)
        reddit_api = json.loads(fd.read())
        fd.close()

        cringe = []

        for i in reddit_api['data']['children']:
            url = i['data']['url']
            title = i['data']['title']

            if 'imgur' in url:

                if 'http://i.imgur.com' in url:  #force https
                    url = 'https://i.imgur.com/%s' % (url.split('/')[3])

                if 'http://' in url and '/a/' not in url:   #direct URLs
                    if 'gallery' in url:
                        url = 'https://i.imgur.com/%s.jpg' % (url.split('/')[4])
                    else:
                        url = 'https://i.imgur.com/%s.jpg' % (url.split('/')[3])

            cringe.append([title, url])

        item = random.choice(cringe)
        return self.msg(channel, str(item[0] + " " + item[1]))

    except Exception, e:
        return self.msg('#the_kgb', str(e))

class api:
	def msg(self, channel, text):
		return "[%s] %s" % (channel, text)

if __name__ == "__main__":
    api = api()
    u = "joe!username@hostmask"
    c = '#test'

    if callback(api, '', True, channel=c, user=u, msg='^reddit') != '[%s] Please specify a subreddit!' % (c):
        print '[TESTFAIL] no arguments'
        exit(1)

    if callback(api, '', True, channel=c, user=u, msg='^reddit fatpeoplehate') != '[#the_kgb] HTTP Error 404: Not Found':
        print '[TESTFAIL] error catcher'
        exit(1)

    if not callback(api, '', True, channel=c, user=u, msg='^reddit fatlogic').startswith('[%s] ' % (c)):
        print '[TESTFAIL] Subreddit loader'
        exit(1)
<|endoftext|>


<commit_before>#! /usr/bin/env python
import os
import json
import zipfile
import argparse
import re
ver = '0.1.1'
abt = \
    """
    Script to convert a Chrome / Opera WebExtension to a Firefox-compatible WebExtension archive.
    Creates a compressed zip archive named from manifest keys <version_name>.xpi  or <name>_firefox_<version>.xpi.
    By Steven Eardley | Cottage Labs LLP | steve@cottagelabs.com
    """

parser = argparse.ArgumentParser(description=abt, version=ver)
parser.add_argument("-d",
                    "--dir",
                    default="..",
                    help="directory to pack (with manifest.json at its root)."
                         "Defaults to .. so this script can used in a submodule")
parser.add_argument("-i",
                    "--id",
                    default="firefox_extension@cottagelabs.com",
                    help="extension ID to be added to the manifest. Default is firefox_extension@cottagelabs.com")
parser.add_argument("-m",
                    "--min_version",
                    default="45.0.0",
                    help="version to put as strict_min_version for Firefox. Defaults to 45.0.0")
args = parser.parse_args()

ffx_manifest_extras = {
    'applications': {
        'gecko': {
            'id': args.id,
            'strict_min_version': args.min_version
        }
    }
}

chrome_manifest = None
try:
    with open(args.dir + '/manifest.json') as f:
        try:
            chrome_manifest = json.load(f)
            # change version string to firefox
            try:
                chrome_manifest["version_name"] = chrome_manifest["version_name"].replace('chrome', 'firefox')
            except KeyError:
                # no version_name, pass
                pass

            # add firefox keys to manifest
            chrome_manifest.update(ffx_manifest_extras)
        except ValueError:
            print "Error: could not parse manifest file."
            exit(1)
except IOError:
    print "Error: problem reading manifest file or file not found."
    exit(1)

if chrome_manifest is None:
    print "Error: no usable manifest file found."
    exit(1)

try:
    name = chrome_manifest['version_name']
except KeyError:
    name = "{0}_firefox_{1}".format(chrome_manifest['name'], chrome_manifest['version'])
archive_filename = '{0}.xpi'.format(name)

with zipfile.ZipFile(file=archive_filename, mode='w') as xpi_zip:
    archive_root = args.dir if args.dir.endswith('/') else args.dir + '/'
    match_root = re.compile('^{0}'.format(archive_root))

    # write all files apart from the manifest
    for root, dirs, files in os.walk(args.dir):
        # exclude hidden files and directories
        files = [f for f in files if not f.startswith('.')]
        dirs[:] = [d for d in dirs if not d.startswith('.')]

        for fi in files:
            # add all files to archive except any old .xpi, the old manifest and this script
            if fi != 'manifest.json' and fi != 'pack_ffx.py' and not fi.endswith(".xpi"):
                xpi_zip.write(filename=os.path.join(root, fi),
                              arcname=match_root.sub('', os.path.join(root, fi)),
                              compress_type=zipfile.ZIP_DEFLATED)

    # write the updated manifest
    xpi_zip.writestr('manifest.json', json.dumps(chrome_manifest), compress_type=zipfile.ZIP_DEFLATED)

    print "Done. New archive at {0} including:\n".format(archive_filename)
    xpi_zip.printdir()

    xpi_zip.close()
<commit_msg>Changed strict minimum version default to one that's actually valid.<commit_after>#! /usr/bin/env python
import os
import json
import zipfile
import argparse
import re
ver = '0.1.2'
abt = \
    """
    Script to convert a Chrome / Opera WebExtension to a Firefox-compatible WebExtension archive.
    Creates a compressed zip archive named from manifest keys <version_name>.xpi  or <name>_firefox_<version>.xpi.
    By Steven Eardley | Cottage Labs LLP | steve@cottagelabs.com
    """

parser = argparse.ArgumentParser(description=abt, version=ver)
parser.add_argument("-d",
                    "--dir",
                    default="..",
                    help="directory to pack (with manifest.json at its root)."
                         "Defaults to .. so this script can used in a submodule")
parser.add_argument("-i",
                    "--id",
                    default="firefox_extension@cottagelabs.com",
                    help="extension ID to be added to the manifest. Default is firefox_extension@cottagelabs.com")
parser.add_argument("-m",
                    "--min_version",
                    default="45.0",
                    help="version to put as strict_min_version for Firefox. Defaults to 45.0")
args = parser.parse_args()

ffx_manifest_extras = {
    'applications': {
        'gecko': {
            'id': args.id,
            'strict_min_version': args.min_version
        }
    }
}

chrome_manifest = None
try:
    with open(args.dir + '/manifest.json') as f:
        try:
            chrome_manifest = json.load(f)
            # change version string to firefox
            try:
                chrome_manifest["version_name"] = chrome_manifest["version_name"].replace('chrome', 'firefox')
            except KeyError:
                # no version_name, pass
                pass

            # add firefox keys to manifest
            chrome_manifest.update(ffx_manifest_extras)
        except ValueError:
            print "Error: could not parse manifest file."
            exit(1)
except IOError:
    print "Error: problem reading manifest file or file not found."
    exit(1)

if chrome_manifest is None:
    print "Error: no usable manifest file found."
    exit(1)

try:
    name = chrome_manifest['version_name']
except KeyError:
    name = "{0}_firefox_{1}".format(chrome_manifest['name'], chrome_manifest['version'])
archive_filename = '{0}.xpi'.format(name)

with zipfile.ZipFile(file=archive_filename, mode='w') as xpi_zip:
    archive_root = args.dir if args.dir.endswith('/') else args.dir + '/'
    match_root = re.compile('^{0}'.format(archive_root))

    # write all files apart from the manifest
    for root, dirs, files in os.walk(args.dir):
        # exclude hidden files and directories
        files = [f for f in files if not f.startswith('.')]
        dirs[:] = [d for d in dirs if not d.startswith('.')]

        for fi in files:
            # add all files to archive except any old .xpi, the old manifest and this script
            if fi != 'manifest.json' and fi != 'pack_ffx.py' and not fi.endswith(".xpi"):
                xpi_zip.write(filename=os.path.join(root, fi),
                              arcname=match_root.sub('', os.path.join(root, fi)),
                              compress_type=zipfile.ZIP_DEFLATED)

    # write the updated manifest
    xpi_zip.writestr('manifest.json', json.dumps(chrome_manifest), compress_type=zipfile.ZIP_DEFLATED)

    print "Done. New archive at {0} including:\n".format(archive_filename)
    xpi_zip.printdir()

    xpi_zip.close()
<|endoftext|>