<commit_before># -*- coding: utf-8 -*-

"""
    marrie
    ~~~~~~

    A simple podcast client that runs on the Command Line Interface.

    :copyright: (c) 2010-2012 by Rafael Goncalves Martins
    :license: BSD, see LICENSE for more details.
"""

__all__ = ['MarrieError', 'Config', 'Podcast', 'Cli', 'main']

__author__ = 'Rafael Goncalves Martins'
__email__ = 'rafael@rafaelmartins.eng.br'

__description__ = 'A simple podcast client that runs on the Command Line ' \
                'Interface.'
__url__ = 'http://projects.rafaelmartins.eng.br/marrie/'
__copyright__ = '(c) 2010-2012 %s <%s>' % (__author__, __email__)
__license__ = 'BSD'

__version__ = '0.3'

import argparse
import codecs
import feedparser
import json
import os
import posixpath
import random
import shutil
import subprocess
import sys
from collections import OrderedDict
from ConfigParser import ConfigParser

config_file = '''\
[config]

# Fetch command to download the files.
#
# Examples:
#   wget --limit-rate=30k -c -O %(file)s %(url)s
#   curl --limit-rate 30K -C - -o %(file)s %(url)s
fetch_command = wget -c -O %(file)s %(url)s

# Player command to play the files
#
# Examples:
#   mplayer %(file)s
#   mpg123 %(file)s
player_command = mplayer %(file)s

# Media directory to store the files
media_dir = ~/podcasts

[podcast]

# List of feeds of your podcasts, in the format:
#   podcast_id = http://example.org/rss/feed.xml

'''

class MarrieError(Exception):
    pass

class Config(object):

    _raw_options = ('fetch_command', 'player_command')
    _options = ('media_dir',)
    _expanduser = ('media_dir',)

    def __init__(self, my_file):
        my_file = os.path.expanduser(my_file)
        if not os.path.exists(my_file):
            with codecs.open(my_file, 'w', encoding='utf-8') as fp:
                fp.write(config_file)
            raise MarrieError(
                'Missing config file: %s. It will be created for you.' % my_file)
        self._cp = ConfigParser()
        self._cp.read(my_file)
        for opt in (self._raw_options + self._options):
            if not self._cp.has_option('config', opt):
                raise MarrieError('Missing needed config option: config:%s' \
                                  % opt)

    def __getattr__(self, attr):
        opt = None
        if attr in self._raw_options:
            opt = self._cp.get('config', attr, True)
        elif attr in self._options:
            opt = self._cp.get('config', attr)
        elif attr == 'podcast':
            opt = OrderedDict(self._cp.items('podcast'))
        if opt is None:
            raise AttributeError(attr)
        if attr in self._expanduser and not isinstance(opt, dict):
            return os.path.expanduser(opt)
        return opt

class Podcast(object):

    def __init__(self, config, pid):
        self.config = config
        if pid not in self.config.podcast:
            raise MarrieError('Invalid podcast ID: %s' % pid)
        self.pid = pid
        self.media_dir = os.path.join(self.config.media_dir, self.pid)
        if not os.path.exists(self.media_dir):
            os.makedirs(self.media_dir)
        self._cache_file = os.path.join(self.media_dir, '.cache')
        self._latest_file = os.path.join(self.media_dir, '.latest')

    ### Subprocess wrappers ###

    def _fetch(self, url):
        filepath = os.path.join(self.media_dir, posixpath.basename(url))
        part_file = filepath + '.part'
        rv = subprocess.call(self.config.fetch_command % \
                             dict(url=url, file=part_file), shell=True)
        if rv != os.EX_OK:
            raise MarrieError('Failed to download the file (%s): %i' % \
                              (url, rv))
        try:
            shutil.move(part_file, filepath)
        except Exception, err:
            raise MarrieError('Failed to save the file (%s): %s' % \
                              (filepath, str(err)))
        else:
            self.set_latest(filepath)

    def _play(self, filename):
        filepath = os.path.join(self.media_dir, os.path.basename(filename))
        rv = subprocess.call(self.config.player_command % dict(file=filepath),
                             shell=True)
        if rv != os.EX_OK:
            raise MarrieError('Failed to play the file (%s): %i' % \
                              (filepath, rv))

    ### Internal helpers ###

    def _load_cache(self):
        try:
            with codecs.open(self._cache_file, encoding='utf-8') as fp:
                return json.load(fp)
        except Exception, err:
            raise MarrieError('Failed to load cache (%s): %s' % \
                              (self._cache_file, str(err)))

    def _convert_oldstyle_latest(self):
        old_latest = os.path.join(self.media_dir, 'LATEST')
        if os.path.exists(old_latest):
            try:
                with codecs.open(old_latest, encoding='utf-8') as fp:
                    os.symlink(fp.read().strip(), self._latest_file)
            except Exception, err:
                raise MarrieError('Failed to convert old-style LATEST file ' \
                                  'to symlink: %s' % str(err))
            else:
                os.unlink(old_latest)

    ### Action helpers ###

    def list_chapters(self):
        if os.path.exists(self._cache_file):
            return self._load_cache()
        return []

    def list_fetched_chapters(self):
        chapters = os.listdir(self.media_dir)
        mylist = []
        for chapter in chapters:
            if chapter not in ('.cache', '.latest') and \
               not chapter.endswith('.part'):
                mylist.append(os.path.join(self.media_dir, chapter))
        return mylist

    def sync(self):
        self._convert_oldstyle_latest()
        purl = self.config.podcast[self.pid]
        try:
            rss = feedparser.parse(purl)
        except Exception, err:
            raise MarrieError('Failed to parse the feed (%s): %s' % \
                              (purl, str(err)))
        chapters = []
        for entry in rss.entries:
            for link in entry.links:
                if link.rel == 'enclosure':
                    category = link.type.split('/')[0]
                    if category in ('audio', 'video'):
                        chapters.append(link.href)
        try:
            with codecs.open(self._cache_file, 'w', encoding='utf-8') as fp:
                json.dump(chapters, fp)
        except Exception, err:
            raise MarrieError('Failed to save cache (%s): %s' % \
                              (self._cache_file, str(err)))

    def fetch(self, chapter_id):
        chapters = self.list_chapters()
        chapter_id = chapter_id - 1
        try:
            chapter = chapters[chapter_id]
        except IndexError:
            raise MarrieError('Invalid chapter identifier.')
        else:
            self._fetch(chapter)

    def fetch_latest(self):
        chapters = self.list_chapters()
        if len(chapters) == 0:
            raise MarrieError('No chapters available.')
        if os.path.exists(os.path.join(self.media_dir,
                                       posixpath.basename(chapters[0]))):
            raise MarrieError('No newer podcast available.')
        self._fetch(chapters[0])

    def play(self, chapter_id):
        if isinstance(chapter_id, int):
            chapters = self.list_fetched_chapters()
            chapter_id = chapter_id - 1
            try:
                chapter = chapters[chapter_id]
            except IndexError:
                raise MarrieError('Invalid chapter identifier.')
        else:
            chapter = chapter_id
        self._play(chapter)

    def play_latest(self):
        self._play(self.get_latest())

    def play_random(self):
        chapters = self.list_fetched_chapters()
        if not len(chapters):
            raise MarrieError('No chapters available.')
        self.play(random.choice(chapters))

    def get_latest(self):
        if not os.path.exists(self._latest_file):
            raise MarrieError('No podcast file registered as latest.')
        latest_file = os.path.realpath(self._latest_file)
        if not os.path.exists(latest_file):
            raise MarrieError('Broken symlink: %s -> %s' % (self._latest_file,
                                                            latest_file))
        return latest_file

    def set_latest(self, url):
        try:
            if os.path.exists(self._latest_file):
                os.unlink(self._latest_file)
            os.symlink(posixpath.basename(url), self._latest_file)
        except Exception, err:
            raise MarrieError('Failed to create the .latest symlink: %s' % \
                              str(err))

class Cli(object):

    _required_pid = ('get', 'play', 'play_random')

    def __init__(self):
        self.parser = argparse.ArgumentParser(description=__description__)
        self.parser.add_argument('podcast_id', nargs='?', metavar='PODCAST_ID',
                                 help='podcast identifier, from the '
                                 'configuration file')
        self.parser.add_argument('chapter_id', nargs='?', metavar='CHAPTER_ID',
                                 help='chapter identifier, local for '
                                 '`--play\', remote for `--get\'. This '
                                 'identifier is variable and is available on '
                                 '`--list CHAPTER_ID\'', type=int)
        self.parser.add_argument('-v', '--version', action='version',
                                 version='%%(prog)s %s' % __version__)
        self.parser.add_argument('--config-file', metavar='FILE',
                                 dest='config_file', help='configuration file '
                                 'to be used. It will override the default '
                                 'file `~/.marrie\'')
        self.group = self.parser.add_mutually_exclusive_group()
        self.group.add_argument('-s', '--sync', action='store_const',
                                dest='callback', const=self.cmd_sync,
                                help='syncronize the local cache of podcast '
                                'chapters available for download, for a given '
                                'PODCAST_ID, or for all available feeds')
        self.group.add_argument('-l', '--list', action='store_const',
                                dest='callback', const=self.cmd_list,
                                help='list all the feeds available or all the '
                                'chapters available for a given PODCAST_ID')
        self.group.add_argument('-g', '--get', action='store_const',
                                dest='callback', const=self.cmd_get,
                                help='fetch the latest chapter available for '
                                'a given PODCAST_ID, if no CHAPTER_ID is '
                                'provided')
        self.group.add_argument('-p', '--play', action='store_const',
                                dest='callback', const=self.cmd_play,
                                help='play the latest chapter fetched for '
                                'a given PODCAST_ID, if no CHAPTER_ID is '
                                'provided')
        self.group.add_argument('-r', '--play-random', action='store_const',
                                dest='callback', const=self.cmd_play_random,
                                help='play a random chapter from the fetched '
                                'for a given PODCAST_ID')

    def run(self):
        self.args = self.parser.parse_args()
        self.config = Config(self.args.config_file or '~/.marrie')
        callback = self.args.callback
        if callback is None:
            self.parser.print_help()
            return os.EX_USAGE
        if callback.__name__.lstrip('cmd_') in self._required_pid:
            if self.args.podcast_id is None:
                self.parser.error('one argument is required.')
        if self.args.podcast_id is not None:
            self.podcast = Podcast(self.config, self.args.podcast_id)
        return callback()

    ### Commands ###

    def cmd_sync(self):
        if self.args.podcast_id is not None:
            print 'Syncronizing feed "%s".' % self.args.podcast_id
            self.podcast.sync()
            return os.EX_OK
        for pid in self.config.podcast:
            print 'Syncronizing feed "%s".' % pid
            podcast = Podcast(self.config, pid)
            podcast.sync()

    def cmd_list(self):
        if self.args.podcast_id is None:
            print 'Podcast feeds available:'
            print
            for pid in self.config.podcast:
                print '    %s - %s' % (pid, self.config.podcast[pid])
            print
            return os.EX_OK
        else:
            print 'Fetched files available for "%s" (sorted by name):' \
                  % self.args.podcast_id
            print
            count = 1
            for filepath in self.podcast.list_fetched_chapters():
                print '    %i: %s' % (count, os.path.basename(filepath))
                count += 1
            if count == 1:
                print '    **** No fetched files.'
            print
            print 'Remote files available for "%s" (reverse sorted by date):' \
                  % self.args.podcast_id
            print
            count = 1
            for url in self.podcast.list_chapters():
                print '    %i: %s' % (count, posixpath.basename(url))
                count += 1
            if count == 1:
                print '    **** No remote files. Try running this script ' \
                      'with `--sync\''
            print

    def cmd_get(self):
        if self.args.chapter_id is None:
            print 'Fetching the latest chapter available for "%s"' % \
                  self.args.podcast_id
            print
            self.podcast.fetch_latest()
            return os.EX_OK
        print 'Fetching chapter "%i" for "%s"' % (self.args.chapter_id,
                                                  self.args.podcast_id)
        print
        self.podcast.fetch(self.args.chapter_id)

    def cmd_play(self):
        if self.args.chapter_id is None:
            print 'Playing the latest chapter fetched for "%s"' % \
                  self.args.podcast_id
            print
            self.podcast.play_latest()
            return os.EX_OK
        print 'Playing chapter "%i" for "%s"' % (self.args.chapter_id,
                                                 self.args.podcast_id)
        print
        self.podcast.play(self.args.chapter_id)

    def cmd_play_random(self):
        print 'Playing a random chapter available for "%s"' % \
              self.args.podcast_id
        print
        self.podcast.play_random()

def main():
    cli = Cli()
    try:
        return cli.run()
    except KeyboardInterrupt:
        print >> sys.stderr, 'Interrupted'
    except MarrieError, err:
        print >> sys.stderr, 'error: %s' % err
    return 1

if __name__ == '__main__':
    sys.exit(main())
<commit_msg>start new version<commit_after># -*- coding: utf-8 -*-

"""
    marrie
    ~~~~~~

    A simple podcast client that runs on the Command Line Interface.

    :copyright: (c) 2010-2012 by Rafael Goncalves Martins
    :license: BSD, see LICENSE for more details.
"""

__all__ = ['MarrieError', 'Config', 'Podcast', 'Cli', 'main']

__author__ = 'Rafael Goncalves Martins'
__email__ = 'rafael@rafaelmartins.eng.br'

__description__ = 'A simple podcast client that runs on the Command Line ' \
                'Interface.'
__url__ = 'http://projects.rafaelmartins.eng.br/marrie/'
__copyright__ = '(c) 2010-2012 %s <%s>' % (__author__, __email__)
__license__ = 'BSD'

__version__ = '0.3+'

import argparse
import codecs
import feedparser
import json
import os
import posixpath
import random
import shutil
import subprocess
import sys
from collections import OrderedDict
from ConfigParser import ConfigParser

config_file = '''\
[config]

# Fetch command to download the files.
#
# Examples:
#   wget --limit-rate=30k -c -O %(file)s %(url)s
#   curl --limit-rate 30K -C - -o %(file)s %(url)s
fetch_command = wget -c -O %(file)s %(url)s

# Player command to play the files
#
# Examples:
#   mplayer %(file)s
#   mpg123 %(file)s
player_command = mplayer %(file)s

# Media directory to store the files
media_dir = ~/podcasts

[podcast]

# List of feeds of your podcasts, in the format:
#   podcast_id = http://example.org/rss/feed.xml

'''

class MarrieError(Exception):
    pass

class Config(object):

    _raw_options = ('fetch_command', 'player_command')
    _options = ('media_dir',)
    _expanduser = ('media_dir',)

    def __init__(self, my_file):
        my_file = os.path.expanduser(my_file)
        if not os.path.exists(my_file):
            with codecs.open(my_file, 'w', encoding='utf-8') as fp:
                fp.write(config_file)
            raise MarrieError(
                'Missing config file: %s. It will be created for you.' % my_file)
        self._cp = ConfigParser()
        self._cp.read(my_file)
        for opt in (self._raw_options + self._options):
            if not self._cp.has_option('config', opt):
                raise MarrieError('Missing needed config option: config:%s' \
                                  % opt)

    def __getattr__(self, attr):
        opt = None
        if attr in self._raw_options:
            opt = self._cp.get('config', attr, True)
        elif attr in self._options:
            opt = self._cp.get('config', attr)
        elif attr == 'podcast':
            opt = OrderedDict(self._cp.items('podcast'))
        if opt is None:
            raise AttributeError(attr)
        if attr in self._expanduser and not isinstance(opt, dict):
            return os.path.expanduser(opt)
        return opt

class Podcast(object):

    def __init__(self, config, pid):
        self.config = config
        if pid not in self.config.podcast:
            raise MarrieError('Invalid podcast ID: %s' % pid)
        self.pid = pid
        self.media_dir = os.path.join(self.config.media_dir, self.pid)
        if not os.path.exists(self.media_dir):
            os.makedirs(self.media_dir)
        self._cache_file = os.path.join(self.media_dir, '.cache')
        self._latest_file = os.path.join(self.media_dir, '.latest')

    ### Subprocess wrappers ###

    def _fetch(self, url):
        filepath = os.path.join(self.media_dir, posixpath.basename(url))
        part_file = filepath + '.part'
        rv = subprocess.call(self.config.fetch_command % \
                             dict(url=url, file=part_file), shell=True)
        if rv != os.EX_OK:
            raise MarrieError('Failed to download the file (%s): %i' % \
                              (url, rv))
        try:
            shutil.move(part_file, filepath)
        except Exception, err:
            raise MarrieError('Failed to save the file (%s): %s' % \
                              (filepath, str(err)))
        else:
            self.set_latest(filepath)

    def _play(self, filename):
        filepath = os.path.join(self.media_dir, os.path.basename(filename))
        rv = subprocess.call(self.config.player_command % dict(file=filepath),
                             shell=True)
        if rv != os.EX_OK:
            raise MarrieError('Failed to play the file (%s): %i' % \
                              (filepath, rv))

    ### Internal helpers ###

    def _load_cache(self):
        try:
            with codecs.open(self._cache_file, encoding='utf-8') as fp:
                return json.load(fp)
        except Exception, err:
            raise MarrieError('Failed to load cache (%s): %s' % \
                              (self._cache_file, str(err)))

    def _convert_oldstyle_latest(self):
        old_latest = os.path.join(self.media_dir, 'LATEST')
        if os.path.exists(old_latest):
            try:
                with codecs.open(old_latest, encoding='utf-8') as fp:
                    os.symlink(fp.read().strip(), self._latest_file)
            except Exception, err:
                raise MarrieError('Failed to convert old-style LATEST file ' \
                                  'to symlink: %s' % str(err))
            else:
                os.unlink(old_latest)

    ### Action helpers ###

    def list_chapters(self):
        if os.path.exists(self._cache_file):
            return self._load_cache()
        return []

    def list_fetched_chapters(self):
        chapters = os.listdir(self.media_dir)
        mylist = []
        for chapter in chapters:
            if chapter not in ('.cache', '.latest') and \
               not chapter.endswith('.part'):
                mylist.append(os.path.join(self.media_dir, chapter))
        return mylist

    def sync(self):
        self._convert_oldstyle_latest()
        purl = self.config.podcast[self.pid]
        try:
            rss = feedparser.parse(purl)
        except Exception, err:
            raise MarrieError('Failed to parse the feed (%s): %s' % \
                              (purl, str(err)))
        chapters = []
        for entry in rss.entries:
            for link in entry.links:
                if link.rel == 'enclosure':
                    category = link.type.split('/')[0]
                    if category in ('audio', 'video'):
                        chapters.append(link.href)
        try:
            with codecs.open(self._cache_file, 'w', encoding='utf-8') as fp:
                json.dump(chapters, fp)
        except Exception, err:
            raise MarrieError('Failed to save cache (%s): %s' % \
                              (self._cache_file, str(err)))

    def fetch(self, chapter_id):
        chapters = self.list_chapters()
        chapter_id = chapter_id - 1
        try:
            chapter = chapters[chapter_id]
        except IndexError:
            raise MarrieError('Invalid chapter identifier.')
        else:
            self._fetch(chapter)

    def fetch_latest(self):
        chapters = self.list_chapters()
        if len(chapters) == 0:
            raise MarrieError('No chapters available.')
        if os.path.exists(os.path.join(self.media_dir,
                                       posixpath.basename(chapters[0]))):
            raise MarrieError('No newer podcast available.')
        self._fetch(chapters[0])

    def play(self, chapter_id):
        if isinstance(chapter_id, int):
            chapters = self.list_fetched_chapters()
            chapter_id = chapter_id - 1
            try:
                chapter = chapters[chapter_id]
            except IndexError:
                raise MarrieError('Invalid chapter identifier.')
        else:
            chapter = chapter_id
        self._play(chapter)

    def play_latest(self):
        self._play(self.get_latest())

    def play_random(self):
        chapters = self.list_fetched_chapters()
        if not len(chapters):
            raise MarrieError('No chapters available.')
        self.play(random.choice(chapters))

    def get_latest(self):
        if not os.path.exists(self._latest_file):
            raise MarrieError('No podcast file registered as latest.')
        latest_file = os.path.realpath(self._latest_file)
        if not os.path.exists(latest_file):
            raise MarrieError('Broken symlink: %s -> %s' % (self._latest_file,
                                                            latest_file))
        return latest_file

    def set_latest(self, url):
        try:
            if os.path.exists(self._latest_file):
                os.unlink(self._latest_file)
            os.symlink(posixpath.basename(url), self._latest_file)
        except Exception, err:
            raise MarrieError('Failed to create the .latest symlink: %s' % \
                              str(err))

class Cli(object):

    _required_pid = ('get', 'play', 'play_random')

    def __init__(self):
        self.parser = argparse.ArgumentParser(description=__description__)
        self.parser.add_argument('podcast_id', nargs='?', metavar='PODCAST_ID',
                                 help='podcast identifier, from the '
                                 'configuration file')
        self.parser.add_argument('chapter_id', nargs='?', metavar='CHAPTER_ID',
                                 help='chapter identifier, local for '
                                 '`--play\', remote for `--get\'. This '
                                 'identifier is variable and is available on '
                                 '`--list CHAPTER_ID\'', type=int)
        self.parser.add_argument('-v', '--version', action='version',
                                 version='%%(prog)s %s' % __version__)
        self.parser.add_argument('--config-file', metavar='FILE',
                                 dest='config_file', help='configuration file '
                                 'to be used. It will override the default '
                                 'file `~/.marrie\'')
        self.group = self.parser.add_mutually_exclusive_group()
        self.group.add_argument('-s', '--sync', action='store_const',
                                dest='callback', const=self.cmd_sync,
                                help='syncronize the local cache of podcast '
                                'chapters available for download, for a given '
                                'PODCAST_ID, or for all available feeds')
        self.group.add_argument('-l', '--list', action='store_const',
                                dest='callback', const=self.cmd_list,
                                help='list all the feeds available or all the '
                                'chapters available for a given PODCAST_ID')
        self.group.add_argument('-g', '--get', action='store_const',
                                dest='callback', const=self.cmd_get,
                                help='fetch the latest chapter available for '
                                'a given PODCAST_ID, if no CHAPTER_ID is '
                                'provided')
        self.group.add_argument('-p', '--play', action='store_const',
                                dest='callback', const=self.cmd_play,
                                help='play the latest chapter fetched for '
                                'a given PODCAST_ID, if no CHAPTER_ID is '
                                'provided')
        self.group.add_argument('-r', '--play-random', action='store_const',
                                dest='callback', const=self.cmd_play_random,
                                help='play a random chapter from the fetched '
                                'for a given PODCAST_ID')

    def run(self):
        self.args = self.parser.parse_args()
        self.config = Config(self.args.config_file or '~/.marrie')
        callback = self.args.callback
        if callback is None:
            self.parser.print_help()
            return os.EX_USAGE
        if callback.__name__.lstrip('cmd_') in self._required_pid:
            if self.args.podcast_id is None:
                self.parser.error('one argument is required.')
        if self.args.podcast_id is not None:
            self.podcast = Podcast(self.config, self.args.podcast_id)
        return callback()

    ### Commands ###

    def cmd_sync(self):
        if self.args.podcast_id is not None:
            print 'Syncronizing feed "%s".' % self.args.podcast_id
            self.podcast.sync()
            return os.EX_OK
        for pid in self.config.podcast:
            print 'Syncronizing feed "%s".' % pid
            podcast = Podcast(self.config, pid)
            podcast.sync()

    def cmd_list(self):
        if self.args.podcast_id is None:
            print 'Podcast feeds available:'
            print
            for pid in self.config.podcast:
                print '    %s - %s' % (pid, self.config.podcast[pid])
            print
            return os.EX_OK
        else:
            print 'Fetched files available for "%s" (sorted by name):' \
                  % self.args.podcast_id
            print
            count = 1
            for filepath in self.podcast.list_fetched_chapters():
                print '    %i: %s' % (count, os.path.basename(filepath))
                count += 1
            if count == 1:
                print '    **** No fetched files.'
            print
            print 'Remote files available for "%s" (reverse sorted by date):' \
                  % self.args.podcast_id
            print
            count = 1
            for url in self.podcast.list_chapters():
                print '    %i: %s' % (count, posixpath.basename(url))
                count += 1
            if count == 1:
                print '    **** No remote files. Try running this script ' \
                      'with `--sync\''
            print

    def cmd_get(self):
        if self.args.chapter_id is None:
            print 'Fetching the latest chapter available for "%s"' % \
                  self.args.podcast_id
            print
            self.podcast.fetch_latest()
            return os.EX_OK
        print 'Fetching chapter "%i" for "%s"' % (self.args.chapter_id,
                                                  self.args.podcast_id)
        print
        self.podcast.fetch(self.args.chapter_id)

    def cmd_play(self):
        if self.args.chapter_id is None:
            print 'Playing the latest chapter fetched for "%s"' % \
                  self.args.podcast_id
            print
            self.podcast.play_latest()
            return os.EX_OK
        print 'Playing chapter "%i" for "%s"' % (self.args.chapter_id,
                                                 self.args.podcast_id)
        print
        self.podcast.play(self.args.chapter_id)

    def cmd_play_random(self):
        print 'Playing a random chapter available for "%s"' % \
              self.args.podcast_id
        print
        self.podcast.play_random()

def main():
    cli = Cli()
    try:
        return cli.run()
    except KeyboardInterrupt:
        print >> sys.stderr, 'Interrupted'
    except MarrieError, err:
        print >> sys.stderr, 'error: %s' % err
    return 1

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


<commit_before>"""
Unit tests for the util.py module.
"""
from pycraft.objects.storage import Storage

def test_create_storage():
    """
    Test create storage.
    """
    storage_obj = Storage()
    assert len(storage_obj.items) == 10, 'Default storage has 10 items'
    assert storage_obj.max_items == 10, 'Default storage max items are 10'
    assert isinstance(storage_obj.items, dict), 'Default storage items is a dictionary'

def test_storage_item():
    """
    Test store_item function.
    """
    storage_obj = Storage()
    storage_obj.store_item(1, 'test')

    assert storage_obj.items[1] == {'test': 1}, 'Item in the position 1 coincide with the inserted item with value 1'
    assert storage_obj.items[0] == dict(), 'Item in the position 0 is empty'

    storage_obj.store_item(1, 'test')
    assert storage_obj.items[1] == {'test': 2}, 'Item in the position 1 coincide with the inserted item with value 2'

    assert storage_obj.store_item(10, 'test2') == False, "Can't store items in positions over max items"
    assert storage_obj.store_item(9, 'test2') == True, "Can store items in last position"

    storage_obj.store_item(2, 'test', 3)
    assert storage_obj.items[2] == {'test': 3}, 'Item in the position 2 coincide with the inserted item with value 3'

def test_retrieve_item_by_position():
    """
    Test store_item function.
    """
    storage_obj = Storage()
    storage_obj.store_item(1, 'test')

    data_test_1 = {"item": 'test', "quantity": 1}

    assert storage_obj.retrieve_item_by_position(1) == data_test_1, \
        'Item in the position 1 coincide with the item with value 1'
    assert storage_obj.retrieve_item_by_position(1) == False, 'Item in the position 1 is empty'

    data_test_2 = {"item": 'test', "quantity": 2}

    storage_obj.store_item(2, 'test', 3)
    assert storage_obj.retrieve_item_by_position(2, 2) == data_test_2, \
        'Item in the position 2 coincide with the item with value 2'

def test_retrieve_item():
    """
    Test store_item function.
    """
    storage_obj = Storage()
    storage_obj.store_item(1, 'test')

    data_test_1 = {"item": 'test', "quantity": 1}

    assert storage_obj.retrieve_item('test') == data_test_1, \
        'Item in the position 1 coincide with the item with value 1'
    assert storage_obj.retrieve_item('test') == False, 'Item in the position 1 is empty'

    data_test_2 = {"item": 'test', "quantity": 2}
    #
    storage_obj.store_item(2, 'test', 3)
    assert storage_obj.retrieve_item('test', 2) == data_test_2, \
        'Item in the position 2 coincide with the item with value 2'

if __name__ == "__main__":
    test_create_storage()
    test_storage_item()
    test_retrieve_item_by_position()
    test_retrieve_item()
<commit_msg>Fix storage test<commit_after>"""
Unit tests for the util.py module.
"""
from pycraft.objects.storage import Storage

def test_create_storage():
    """
    Test create storage.
    """
    storage_obj = Storage()
    assert len(storage_obj.items) == 10, 'Default storage has 10 items'
    assert storage_obj.max_items == 10, 'Default storage max items are 10'
    assert isinstance(storage_obj.items, dict), 'Default storage items is a dictionary'

def test_storage_item():
    """
    Test store_item function.
    """
    storage_obj = Storage()
    storage_obj.store_item(1, 'test')

    assert storage_obj.items[1] == {'test': 1}, 'Item in the position 1 coincide with the inserted item with value 1'
    assert storage_obj.items[0] == dict(), 'Item in the position 0 is empty'

    storage_obj.store_item(1, 'test')
    assert storage_obj.items[1] == {'test': 2}, 'Item in the position 1 coincide with the inserted item with value 2'

    assert storage_obj.store_item(10, 'test2') is False, "Can't store items in positions over max items"
    assert storage_obj.store_item(9, 'test2') is True, "Can store items in last position"

    storage_obj.store_item(2, 'test', 3)
    assert storage_obj.items[2] == {'test': 3}, 'Item in the position 2 coincide with the inserted item with value 3'

def test_retrieve_item_by_position():
    """
    Test store_item function.
    """
    storage_obj = Storage()
    storage_obj.store_item(1, 'test')

    data_test_1 = {"item": 'test', "quantity": 1}

    assert storage_obj.retrieve_item_by_position(1) == data_test_1, \
        'Item in the position 1 coincide with the item with value 1'
    assert storage_obj.retrieve_item_by_position(1) is False, 'Item in the position 1 is empty'

    data_test_2 = {"item": 'test', "quantity": 2}

    storage_obj.store_item(2, 'test', 3)
    assert storage_obj.retrieve_item_by_position(2, 2) == data_test_2, \
        'Item in the position 2 coincide with the item with value 2'

def test_retrieve_item():
    """
    Test store_item function.
    """
    storage_obj = Storage()
    storage_obj.store_item(1, 'test')

    data_test_1 = {"item": 'test', "quantity": 1}

    assert storage_obj.retrieve_item('test') == data_test_1, \
        'Item in the position 1 coincide with the item with value 1'
    assert storage_obj.retrieve_item('test') is False, 'Item in the position 1 is empty'

    data_test_2 = {"item": 'test', "quantity": 2}
    #
    storage_obj.store_item(2, 'test', 3)
    assert storage_obj.retrieve_item('test', 2) == data_test_2, \
        'Item in the position 2 coincide with the item with value 2'

if __name__ == "__main__":
    test_create_storage()
    test_storage_item()
    test_retrieve_item_by_position()
    test_retrieve_item()
<|endoftext|>


<commit_before>import taichi as ti
import numpy as np

if ti.has_pytorch():
  import torch

def torch_test(func):
  if ti.has_pytorch():
    return ti.all_archs(func)
  else:
    return lambda x: None

@torch_test
def test_io_devices():
  n = 32
  x = ti.var(dt=ti.i32, shape=n)

  @ti.kernel
  def load(y: ti.ext_arr()):
    for i in x:
      x[i] = y[i] + 10

  @ti.kernel
  def inc():
    for i in x:
      x[i] += i

  @ti.kernel
  def store(y: ti.ext_arr()):
    for i in x:
      y[i] = x[i] * 2

  devices = ['cpu']
  if torch.cuda.is_available():
    devices.append('cuda:0')
  for device in devices:
    y = torch.Tensor(np.ones(shape=n, dtype=np.int32)).to(device)

    load(y)
    inc()
    store(y)

    y = y.cpu().numpy()

    for i in range(n):
      assert y[i] == (11 + i) * 2

@torch_test
def test_io():
  n = 32

  @ti.kernel
  def torch_kernel(t: ti.ext_arr(), o: ti.ext_arr()):
    for i in range(n):
      o[i] = t[i] * t[i]

  @ti.kernel
  def torch_kernel_2(t_grad: ti.ext_arr(), t: ti.ext_arr(),
                     o_grad: ti.ext_arr()):
    for i in range(n):
      t_grad[i] = 2 * t[i] * o_grad[i]

  class Sqr(torch.autograd.Function):

    @staticmethod
    def forward(ctx, inp):
      outp = torch.zeros_like(inp)
      ctx.save_for_backward(inp)
      torch_kernel(inp, outp)
      return outp

    @staticmethod
    def backward(ctx, outp_grad):
      outp_grad = outp_grad.contiguous()
      inp_grad = torch.zeros_like(outp_grad)
      inp, = ctx.saved_tensors
      torch_kernel_2(inp_grad, inp, outp_grad)
      return inp_grad

  sqr = Sqr.apply
  X = torch.tensor(2 * np.ones((n,), dtype=np.float32), requires_grad=True)
  sqr(X).sum().backward()
  ret = X.grad.cpu()
  for i in range(n):
    assert ret[i] == 4

@torch_test
def test_io_2d():
  n = 32

  @ti.kernel
  def torch_kernel(t: ti.ext_arr(), o: ti.ext_arr()):
    for i in range(n):
      for j in range(n):
        o[i, j] = t[i, j] * t[i, j]

  class Sqr(torch.autograd.Function):

    @staticmethod
    def forward(ctx, inp):
      outp = torch.zeros_like(inp)
      torch_kernel(inp, outp)
      return outp

  sqr = Sqr.apply
  X = torch.tensor(2 * np.ones((n, n), dtype=np.float32), requires_grad=True)
  val = sqr(X).sum()
  assert val == 2 * 2 * n * n

@torch_test
def test_io_3d():
  n = 16

  @ti.kernel
  def torch_kernel(t: ti.ext_arr(), o: ti.ext_arr()):
    for i in range(n):
      for j in range(n):
        for k in range(n):
          o[i, j, k] = t[i, j, k] * t[i, j, k]

  class Sqr(torch.autograd.Function):

    @staticmethod
    def forward(ctx, inp):
      outp = torch.zeros_like(inp)
      torch_kernel(inp, outp)
      return outp

  sqr = Sqr.apply
  X = torch.tensor(2 * np.ones((n, n, n), dtype=np.float32), requires_grad=True)
  val = sqr(X).sum()
  assert val == 2 * 2 * n * n * n

@torch_test
def test_io_simple():
  n = 32

  x1 = ti.var(ti.f32, shape=(n, n))
  t1 = torch.tensor(2 * np.ones((n, n), dtype=np.float32))

  x2 = ti.Matrix(2, 3, ti.f32, shape=(n, n))
  t2 = torch.tensor(2 * np.ones((n, n, 2, 3), dtype=np.float32))

  x1.from_torch(t1)
  for i in range(n):
    for j in range(n):
      assert x1[i, j] == 2

  x2.from_torch(t2)
  for i in range(n):
    for j in range(n):
      for k in range(2):
        for l in range(3):
          assert x2[i, j][k, l] == 2

  t3 = x2.to_torch()
  assert (t2 == t3).all()

@torch_test
def test_io_simple():
  mat = ti.Matrix(2, 6, dt=ti.f32, shape=(), needs_grad=True)
  zeros = torch.zeros((2, 6))
  zeros[1, 2] = 3
  mat.from_torch(zeros + 1)

  assert mat[None][1, 2] == 4

  zeros = mat.to_torch()
  assert zeros[1, 2] == 4
<commit_msg>fix non-cuda build<commit_after>import taichi as ti
import numpy as np

if ti.has_pytorch():
  import torch

def torch_test(func):
  if ti.has_pytorch():
    return ti.all_archs(func)
  else:
    return lambda: None

@torch_test
def test_io_devices():
  n = 32
  x = ti.var(dt=ti.i32, shape=n)

  @ti.kernel
  def load(y: ti.ext_arr()):
    for i in x:
      x[i] = y[i] + 10

  @ti.kernel
  def inc():
    for i in x:
      x[i] += i

  @ti.kernel
  def store(y: ti.ext_arr()):
    for i in x:
      y[i] = x[i] * 2

  devices = ['cpu']
  if torch.cuda.is_available():
    devices.append('cuda:0')
  for device in devices:
    y = torch.Tensor(np.ones(shape=n, dtype=np.int32)).to(device)

    load(y)
    inc()
    store(y)

    y = y.cpu().numpy()

    for i in range(n):
      assert y[i] == (11 + i) * 2

@torch_test
def test_io():
  n = 32

  @ti.kernel
  def torch_kernel(t: ti.ext_arr(), o: ti.ext_arr()):
    for i in range(n):
      o[i] = t[i] * t[i]

  @ti.kernel
  def torch_kernel_2(t_grad: ti.ext_arr(), t: ti.ext_arr(),
                     o_grad: ti.ext_arr()):
    for i in range(n):
      t_grad[i] = 2 * t[i] * o_grad[i]

  class Sqr(torch.autograd.Function):

    @staticmethod
    def forward(ctx, inp):
      outp = torch.zeros_like(inp)
      ctx.save_for_backward(inp)
      torch_kernel(inp, outp)
      return outp

    @staticmethod
    def backward(ctx, outp_grad):
      outp_grad = outp_grad.contiguous()
      inp_grad = torch.zeros_like(outp_grad)
      inp, = ctx.saved_tensors
      torch_kernel_2(inp_grad, inp, outp_grad)
      return inp_grad

  sqr = Sqr.apply
  X = torch.tensor(2 * np.ones((n,), dtype=np.float32), requires_grad=True)
  sqr(X).sum().backward()
  ret = X.grad.cpu()
  for i in range(n):
    assert ret[i] == 4

@torch_test
def test_io_2d():
  n = 32

  @ti.kernel
  def torch_kernel(t: ti.ext_arr(), o: ti.ext_arr()):
    for i in range(n):
      for j in range(n):
        o[i, j] = t[i, j] * t[i, j]

  class Sqr(torch.autograd.Function):

    @staticmethod
    def forward(ctx, inp):
      outp = torch.zeros_like(inp)
      torch_kernel(inp, outp)
      return outp

  sqr = Sqr.apply
  X = torch.tensor(2 * np.ones((n, n), dtype=np.float32), requires_grad=True)
  val = sqr(X).sum()
  assert val == 2 * 2 * n * n

@torch_test
def test_io_3d():
  n = 16

  @ti.kernel
  def torch_kernel(t: ti.ext_arr(), o: ti.ext_arr()):
    for i in range(n):
      for j in range(n):
        for k in range(n):
          o[i, j, k] = t[i, j, k] * t[i, j, k]

  class Sqr(torch.autograd.Function):

    @staticmethod
    def forward(ctx, inp):
      outp = torch.zeros_like(inp)
      torch_kernel(inp, outp)
      return outp

  sqr = Sqr.apply
  X = torch.tensor(2 * np.ones((n, n, n), dtype=np.float32), requires_grad=True)
  val = sqr(X).sum()
  assert val == 2 * 2 * n * n * n

@torch_test
def test_io_simple():
  n = 32

  x1 = ti.var(ti.f32, shape=(n, n))
  t1 = torch.tensor(2 * np.ones((n, n), dtype=np.float32))

  x2 = ti.Matrix(2, 3, ti.f32, shape=(n, n))
  t2 = torch.tensor(2 * np.ones((n, n, 2, 3), dtype=np.float32))

  x1.from_torch(t1)
  for i in range(n):
    for j in range(n):
      assert x1[i, j] == 2

  x2.from_torch(t2)
  for i in range(n):
    for j in range(n):
      for k in range(2):
        for l in range(3):
          assert x2[i, j][k, l] == 2

  t3 = x2.to_torch()
  assert (t2 == t3).all()

@torch_test
def test_io_simple():
  mat = ti.Matrix(2, 6, dt=ti.f32, shape=(), needs_grad=True)
  zeros = torch.zeros((2, 6))
  zeros[1, 2] = 3
  mat.from_torch(zeros + 1)

  assert mat[None][1, 2] == 4

  zeros = mat.to_torch()
  assert zeros[1, 2] == 4
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-
u"""PyTest for :mod:`sirepo.template.srw.py`

:copyright: Copyright (c) 2018 RadiaSoft LLC.  All Rights Reserved.
:license: http://www.apache.org/licenses/LICENSE-2.0.html
"""
from __future__ import absolute_import, division, print_function
import pytest
import zipfile

from pykern import pkresource
from pykern import pkunit
from pykern.pkcollections import PKDict
from sirepo.template import template_common

def test_validate_safe_zip():
    from sirepo.template import srw

    zip_dir = str(pkunit.data_dir() + '/zip_dir')

    # Reject a zip that would overwrite files
    with pkunit.pkexcept(AssertionError):
        srw._validate_safe_zip(zip_dir + '/bad_zip_would_overwrite.zip', zip_dir)

    # Reject a zip that would extract a file above the target directory
    with pkunit.pkexcept(AssertionError):
        srw._validate_safe_zip(zip_dir + '/bad_zip_external_file.zip', zip_dir)

    # Reject a zip with unacceptably large file
    with pkunit.pkexcept(AssertionError):
        srw._validate_safe_zip(zip_dir + '/bad_zip_large_file.zip', zip_dir)

    # Reject a zip with executable permissions set
    with pkunit.pkexcept(AssertionError):
        srw._validate_safe_zip(zip_dir + '/bad_zip_executables.zip', zip_dir)

    # Finally, accept a zip file known to be safe
    srw._validate_safe_zip(zip_dir + '/good_zip.zip', zip_dir, srw.validate_magnet_data_file)

def test_dict_to_from_h5():
    from pykern import pkio
    import h5py

    # _TEST_DICT includes single-valued entries (str and int), an array,
    # and keys that evaluate to ints
    _TEST_DICT = PKDict(
        a_str='A',
        b_dict=PKDict(
            b_str='B',
            b_arr=[0, 1, 2]
        )
    )
    _TEST_DICT['999'] = '999'
    _TEST_DICT['998'] = 998
    _TEST_H5_FILE = 'test.h5'

    pkio.unchecked_remove(_TEST_H5_FILE)
    template_common.write_dict_to_h5(_TEST_DICT, _TEST_H5_FILE)
    d = None
    with h5py.File(_TEST_H5_FILE, 'r') as f:
        d = template_common.h5_to_dict(f)
    pkunit.pkeq(_TEST_DICT, d)
<commit_msg>#3704 - cleanup<commit_after># -*- coding: utf-8 -*-
u"""PyTest for :mod:`sirepo.template.srw.py`

:copyright: Copyright (c) 2018 RadiaSoft LLC.  All Rights Reserved.
:license: http://www.apache.org/licenses/LICENSE-2.0.html
"""
from __future__ import absolute_import, division, print_function
import pytest
import zipfile

from pykern import pkresource
from pykern import pkunit
from sirepo.template import template_common

def test_validate_safe_zip():
    from sirepo.template import srw

    zip_dir = str(pkunit.data_dir() + '/zip_dir')

    # Reject a zip that would overwrite files
    with pkunit.pkexcept(AssertionError):
        srw._validate_safe_zip(zip_dir + '/bad_zip_would_overwrite.zip', zip_dir)

    # Reject a zip that would extract a file above the target directory
    with pkunit.pkexcept(AssertionError):
        srw._validate_safe_zip(zip_dir + '/bad_zip_external_file.zip', zip_dir)

    # Reject a zip with unacceptably large file
    with pkunit.pkexcept(AssertionError):
        srw._validate_safe_zip(zip_dir + '/bad_zip_large_file.zip', zip_dir)

    # Reject a zip with executable permissions set
    with pkunit.pkexcept(AssertionError):
        srw._validate_safe_zip(zip_dir + '/bad_zip_executables.zip', zip_dir)

    # Finally, accept a zip file known to be safe
    srw._validate_safe_zip(zip_dir + '/good_zip.zip', zip_dir, srw.validate_magnet_data_file)

def test_dict_to_from_h5():
    from pykern import pkio
    from pykern.pkcollections import PKDict
    import h5py

    # _TEST_DICT includes single-valued entries (str and int), an array,
    # and keys that evaluate to ints
    _TEST_DICT = PKDict(
        a_str='A',
        b_dict=PKDict(
            b_str='B',
            b_arr=[0, 1, 2]
        )
    )
    _TEST_DICT['999'] = '999'
    _TEST_DICT['998'] = 998
    _TEST_H5_FILE = 'test.h5'

    pkio.unchecked_remove(_TEST_H5_FILE)
    template_common.write_dict_to_h5(_TEST_DICT, _TEST_H5_FILE)
    d = None
    with h5py.File(_TEST_H5_FILE, 'r') as f:
        d = template_common.h5_to_dict(f)
    pkunit.pkeq(_TEST_DICT, d)
<|endoftext|>


<commit_before>import re

from collections import defaultdict

from livestreamer.plugin import Plugin
from livestreamer.plugin.api import http, validate
from livestreamer.stream import HTTPStream, HDSStream, RTMPStream

MEDIA_URL = "http://www.ardmediathek.de/play/media/{0}"
SWF_URL = "http://www.ardmediathek.de/ard/static/player/base/flash/PluginFlash.swf"
HDCORE_PARAMETER = "?hdcore=3.3.0"
QUALITY_MAP = {
    "auto": "auto",
    3: "544p",
    2: "360p",
    1: "288p",
    0: "144p"
}

_url_re = re.compile("http(s)?://(\w+\.)?ardmediathek.de/tv")
_media_id_re = re.compile("/play/config/(\d+)")
_media_schema = validate.Schema({
    "_mediaArray": [{
        "_mediaStreamArray": [{
            validate.optional("_server"): validate.text,
            "_stream": validate.any(validate.text, [validate.text]),
            "_quality": validate.any(int, validate.text)
        }]
    }]
})
_smil_schema = validate.Schema(
    validate.union({
        "base": validate.all(
            validate.xml_find("head/meta"),
            validate.get("base"),
            validate.url(scheme="http")
        ),
        "videos": validate.all(
            validate.xml_findall("body/seq/video"),
            [validate.get("src")]
        )
    })
)

class ard_mediathek(Plugin):
    @classmethod
    def can_handle_url(cls, url):
        return _url_re.match(url)

    def _get_http_streams(self, info):
        name = QUALITY_MAP.get(info["_quality"], "vod")
        urls = info["_stream"]
        if not isinstance(info["_stream"], list):
            urls = [urls]

        streams = {}
        for url in urls:
            stream = HTTPStream(self.session, url)
            if streams:
                streams[name + "_alt"] = stream
            else:
                streams[name] = stream

        return streams

    def _get_hds_streams(self, info):
        # Needs the hdcore parameter added
        url = info["_stream"] + HDCORE_PARAMETER

        return HDSStream.parse_manifest(self.session, url, pvswf=SWF_URL)

    def _get_rtmp_streams(self, info):
        name = QUALITY_MAP.get(info["_quality"], "live")
        params = {
            "rtmp": info["_server"].strip(),
            "playpath": info["_stream"],
            "pageUrl": self.url,
            "swfVfy": SWF_URL,
            "live": True
        }
        stream = RTMPStream(self.session, params)

        return {name: stream}

    def _get_smil_streams(self, info):
        res = http.get(info["_stream"])
        smil = http.xml(res, "SMIL config", schema=_smil_schema)

        streams = {}
        for video in smil["videos"]:
            url = "{0}/{1}{2}".format(smil["base"], video, HDCORE_PARAMETER)
            streams.update(
                HDSStream.parse_manifest(self.session, url, pvswf=SWF_URL)
            )

        return streams

    def _get_streams(self):
        res = http.get(self.url)
        match = _media_id_re.search(res.text)
        if match:
            media_id = match.group(1)
        else:
            return

        res = http.get(MEDIA_URL.format(media_id))
        media = http.json(res, schema=_media_schema)

        streams = defaultdict(list)
        for media in media["_mediaArray"]:
            for stream in media["_mediaStreamArray"]:
                server = stream.get("_server", "").strip()
                stream_ = stream["_stream"]
                if isinstance(stream_, list):
                    if not stream_:
                        continue
                    stream_ = stream_[0]
                stream_ = stream_.strip()

                if server.startswith("rtmp://"):
                    parser = self._get_rtmp_streams
                    parser_name = "RTMP"
                elif stream_.endswith(".f4m"):
                    parser = self._get_hds_streams
                    parser_name = "HDS"
                elif stream_.endswith(".smil"):
                    parser = self._get_smil_streams
                    parser_name = "SMIL"
                elif stream_.startswith("http"):
                    parser = self._get_http_streams
                    parser_name = "HTTP"

                try:
                    for name, stream in parser(stream).items():
                        streams[name].append(stream)
                except IOError as err:
                    self.logger.error("Failed to extract {0} streams: {1}",
                                      parser_name, err)

        return streams

__plugin__ = ard_mediathek
<commit_msg>plugins.ard_mediathek: Use generators instead of dicts.<commit_after>import re

from livestreamer.plugin import Plugin
from livestreamer.plugin.api import http, validate
from livestreamer.stream import HTTPStream, HDSStream, RTMPStream

MEDIA_URL = "http://www.ardmediathek.de/play/media/{0}"
SWF_URL = "http://www.ardmediathek.de/ard/static/player/base/flash/PluginFlash.swf"
HDCORE_PARAMETER = "?hdcore=3.3.0"
QUALITY_MAP = {
    "auto": "auto",
    3: "544p",
    2: "360p",
    1: "288p",
    0: "144p"
}

_url_re = re.compile("http(s)?://(\w+\.)?ardmediathek.de/tv")
_media_id_re = re.compile("/play/config/(\d+)")
_media_schema = validate.Schema({
    "_mediaArray": [{
        "_mediaStreamArray": [{
            validate.optional("_server"): validate.text,
            "_stream": validate.any(validate.text, [validate.text]),
            "_quality": validate.any(int, validate.text)
        }]
    }]
})
_smil_schema = validate.Schema(
    validate.union({
        "base": validate.all(
            validate.xml_find("head/meta"),
            validate.get("base"),
            validate.url(scheme="http")
        ),
        "videos": validate.all(
            validate.xml_findall("body/seq/video"),
            [validate.get("src")]
        )
    })
)

class ard_mediathek(Plugin):
    @classmethod
    def can_handle_url(cls, url):
        return _url_re.match(url)

    def _get_http_streams(self, info):
        name = QUALITY_MAP.get(info["_quality"], "vod")
        urls = info["_stream"]
        if not isinstance(info["_stream"], list):
            urls = [urls]

        for url in urls:
            stream = HTTPStream(self.session, url)
            yield name, stream

    def _get_hds_streams(self, info):
        # Needs the hdcore parameter added
        url = info["_stream"] + HDCORE_PARAMETER
        return HDSStream.parse_manifest(self.session, url, pvswf=SWF_URL).items()

    def _get_rtmp_streams(self, info):
        name = QUALITY_MAP.get(info["_quality"], "live")
        params = {
            "rtmp": info["_server"].strip(),
            "playpath": info["_stream"],
            "pageUrl": self.url,
            "swfVfy": SWF_URL,
            "live": True
        }
        stream = RTMPStream(self.session, params)
        yield name, stream

    def _get_smil_streams(self, info):
        res = http.get(info["_stream"])
        smil = http.xml(res, "SMIL config", schema=_smil_schema)

        for video in smil["videos"]:
            url = "{0}/{1}{2}".format(smil["base"], video, HDCORE_PARAMETER)
            streams = HDSStream.parse_manifest(self.session, url, pvswf=SWF_URL)

            # TODO: Replace with "yield from" when dropping Python 2.
            for stream in streams.items():
                yield stream

    def _get_streams(self):
        res = http.get(self.url)
        match = _media_id_re.search(res.text)
        if match:
            media_id = match.group(1)
        else:
            return

        res = http.get(MEDIA_URL.format(media_id))
        media = http.json(res, schema=_media_schema)

        for media in media["_mediaArray"]:
            for stream in media["_mediaStreamArray"]:
                server = stream.get("_server", "").strip()
                stream_ = stream["_stream"]
                if isinstance(stream_, list):
                    if not stream_:
                        continue
                    stream_ = stream_[0]
                stream_ = stream_.strip()

                if server.startswith("rtmp://"):
                    parser = self._get_rtmp_streams
                    parser_name = "RTMP"
                elif stream_.endswith(".f4m"):
                    parser = self._get_hds_streams
                    parser_name = "HDS"
                elif stream_.endswith(".smil"):
                    parser = self._get_smil_streams
                    parser_name = "SMIL"
                elif stream_.startswith("http"):
                    parser = self._get_http_streams
                    parser_name = "HTTP"

                try:
                    # TODO: Replace with "yield from" when dropping Python 2.
                    for stream in parser(stream):
                        yield stream
                except IOError as err:
                    self.logger.error("Failed to extract {0} streams: {1}",
                                      parser_name, err)

__plugin__ = ard_mediathek
<|endoftext|>


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

# ======================================================================
# matscipy - Python materials science tools
# https://github.com/libAtoms/matscipy
#
# Copyright (2014) James Kermode, King's College London
#                  Lars Pastewka, University of Freiburg
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
# ======================================================================

import pytest

import numpy as np

import ase.constraints
from ase.lattice.compounds import B3
from ase.lattice.cubic import Diamond
from ase.optimize import FIRE
from ase.units import GPa

import matscipy.calculators.manybody.explicit_forms.stillinger_weber as stillinger_weber
import matscipy.calculators.manybody.explicit_forms.kumagai as kumagai
import matscipy.calculators.manybody.explicit_forms.tersoff_brenner as tersoff_brenner
from matscipy.calculators.manybody import Manybody
from matscipy.calculators.manybody.explicit_forms import Kumagai, TersoffBrenner, StillingerWeber
from matscipy.elasticity import full_3x3x3x3_to_Voigt_6x6

###

sx = 1

tests = [
    ("Kumagai-dia-Si", Kumagai(kumagai.Kumagai_Comp_Mat_Sci_39_Si),
     dict(struct=Diamond("Si", size=[sx, sx, sx]),
          Ec=4.630, a0=5.429, C11=166.4, C12=65.3, C44=77.1, C440=120.9)),
    ("StillingerWeber-dia-Si", StillingerWeber(stillinger_weber.Stillinger_Weber_PRB_31_5262_Si),
     dict(struct=Diamond("Si", size=[sx, sx, sx]),
          Ec=4.630, a0=5.431, C11=161.6, C12=81.6, C44=60.3, C440=117.2, B=108.3)),
    ("Tersoff3-dia-C", TersoffBrenner(tersoff_brenner.Tersoff_PRB_39_5566_Si_C),
     dict(struct=Diamond("C", size=[sx, sx, sx]),
          Ec=7.396 - 0.0250, a0=3.566, C11=1067, C12=104, C44=636, C440=671)),
    ("Tersoff3-dia-Si", TersoffBrenner(tersoff_brenner.Tersoff_PRB_39_5566_Si_C),
     dict(struct=Diamond("Si", size=[sx, sx, sx]),
          Ec=4.63, a0=5.432, C11=143, C12=75, C44=69, C440=119, B=98)),
    ("Tersoff3-dia-Si-C", TersoffBrenner(tersoff_brenner.Tersoff_PRB_39_5566_Si_C),
     dict(struct=B3(["Si", "C"], latticeconstant=4.3596, size=[sx, sx, sx]),
          Ec=6.165, a0=4.321, C11=437, C12=118, C440=311, B=224)),
    ("MatsunagaFisherMatsubara-dia-C",
     TersoffBrenner(tersoff_brenner.Matsunaga_Fisher_Matsubara_Jpn_J_Appl_Phys_39_48_B_C_N),
     dict(struct=Diamond("C", size=[sx, sx, sx]),
          Ec=7.396 - 0.0250, a0=3.566, C11=1067, C12=104, C44=636, C440=671)),
    ("MatsunagaFisherMatsubara-dia-B-N",
     TersoffBrenner(tersoff_brenner.Matsunaga_Fisher_Matsubara_Jpn_J_Appl_Phys_39_48_B_C_N),
     dict(struct=B3(["B", "N"], latticeconstant=3.7, size=[sx, sx, sx]),
          Ec=6.63, a0=3.658, B=385)),
]

@pytest.mark.parametrize('test', tests)
def test_cubic_elastic_constants(test):
    name, pot, mat = test

    calculator = Manybody(**pot)
    atoms = mat["struct"]
    atoms.translate([0.1, 0.1, 0.1])
    atoms.set_scaled_positions(atoms.get_scaled_positions())
    atoms.calc = calculator

    FIRE(ase.constraints.StrainFilter(atoms, mask=[1, 1, 1, 0, 0, 0]), logfile=None).run(fmax=0.0001)

    # Ec
    Ec = -atoms.get_potential_energy() / len(atoms)

    # a0
    c1, c2, c3 = atoms.get_cell()
    a0 = np.sqrt(np.dot(c1, c1)) / sx

    # C11, C12, C44
    Caffine = calculator.get_birch_coefficients(atoms)
    Cnonaffine = calculator.get_non_affine_contribution_to_elastic_constants(atoms, tol=1e-5)
    C = full_3x3x3x3_to_Voigt_6x6(Caffine + Cnonaffine)
    C11 = C[0, 0] / GPa
    C12 = C[0, 1] / GPa
    C44 = C[3, 3] / GPa
    C110 = full_3x3x3x3_to_Voigt_6x6(Caffine)[0, 0] / GPa
    C120 = full_3x3x3x3_to_Voigt_6x6(Caffine)[0, 1] / GPa
    C440 = full_3x3x3x3_to_Voigt_6x6(Caffine)[3, 3] / GPa
    B = (C11 + 2 * C12) / 3

    # print to screen
    print()
    print(f'=== {name}===')
    l1 = f'          '
    l2 = f'Computed: '
    l3 = f'Reference:'
    for prop in ['Ec', 'a0', 'C11', 'C110', 'C12', 'C120', 'C44', 'C440', 'B']:
        l1 += prop.rjust(11)
        l2 += f'{locals()[prop]:.2f}'.rjust(11)
        if prop in mat:
            l3 += f'{float(mat[prop]):.2f}'.rjust(11)
        else:
            l3 += '---'.rjust(11)
    print(l1)
    print(l2)
    print(l3)

    # actually test properties
    for prop, value in mat.items():
        if prop != 'struct':
            np.testing.assert_allclose(locals()[prop], value, rtol=0.1)
<commit_msg>Correct value for Ec for Stillinger-Weber<commit_after>#! /usr/bin/env python

# ======================================================================
# matscipy - Python materials science tools
# https://github.com/libAtoms/matscipy
#
# Copyright (2014) James Kermode, King's College London
#                  Lars Pastewka, University of Freiburg
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
# ======================================================================

import pytest

import numpy as np

import ase.constraints
from ase.lattice.compounds import B3
from ase.lattice.cubic import Diamond
from ase.optimize import FIRE
from ase.units import GPa

import matscipy.calculators.manybody.explicit_forms.stillinger_weber as stillinger_weber
import matscipy.calculators.manybody.explicit_forms.kumagai as kumagai
import matscipy.calculators.manybody.explicit_forms.tersoff_brenner as tersoff_brenner
from matscipy.calculators.manybody import Manybody
from matscipy.calculators.manybody.explicit_forms import Kumagai, TersoffBrenner, StillingerWeber
from matscipy.elasticity import full_3x3x3x3_to_Voigt_6x6

###

sx = 1

tests = [
    ("Kumagai-dia-Si", Kumagai(kumagai.Kumagai_Comp_Mat_Sci_39_Si),
     dict(struct=Diamond("Si", size=[sx, sx, sx]),
          Ec=4.630, a0=5.429, C11=166.4, C12=65.3, C44=77.1, C440=120.9)),
    ("StillingerWeber-dia-Si", StillingerWeber(stillinger_weber.Stillinger_Weber_PRB_31_5262_Si),
     dict(struct=Diamond("Si", size=[sx, sx, sx]),
          Ec=4.3363, a0=5.431, C11=161.6, C12=81.6, C44=60.3, C440=117.2, B=108.3)),
    ("Tersoff3-dia-C", TersoffBrenner(tersoff_brenner.Tersoff_PRB_39_5566_Si_C),
     dict(struct=Diamond("C", size=[sx, sx, sx]),
          Ec=7.396 - 0.0250, a0=3.566, C11=1067, C12=104, C44=636, C440=671)),
    ("Tersoff3-dia-Si", TersoffBrenner(tersoff_brenner.Tersoff_PRB_39_5566_Si_C),
     dict(struct=Diamond("Si", size=[sx, sx, sx]),
          Ec=4.63, a0=5.432, C11=143, C12=75, C44=69, C440=119, B=98)),
    ("Tersoff3-dia-Si-C", TersoffBrenner(tersoff_brenner.Tersoff_PRB_39_5566_Si_C),
     dict(struct=B3(["Si", "C"], latticeconstant=4.3596, size=[sx, sx, sx]),
          Ec=6.165, a0=4.321, C11=437, C12=118, C440=311, B=224)),
    ("MatsunagaFisherMatsubara-dia-C",
     TersoffBrenner(tersoff_brenner.Matsunaga_Fisher_Matsubara_Jpn_J_Appl_Phys_39_48_B_C_N),
     dict(struct=Diamond("C", size=[sx, sx, sx]),
          Ec=7.396 - 0.0250, a0=3.566, C11=1067, C12=104, C44=636, C440=671)),
    ("MatsunagaFisherMatsubara-dia-B-N",
     TersoffBrenner(tersoff_brenner.Matsunaga_Fisher_Matsubara_Jpn_J_Appl_Phys_39_48_B_C_N),
     dict(struct=B3(["B", "N"], latticeconstant=3.7, size=[sx, sx, sx]),
          Ec=6.63, a0=3.658, B=385)),
]

@pytest.mark.parametrize('test', tests)
def test_cubic_elastic_constants(test):
    name, pot, mat = test

    calculator = Manybody(**pot)
    atoms = mat["struct"]
    atoms.translate([0.1, 0.1, 0.1])
    atoms.set_scaled_positions(atoms.get_scaled_positions())
    atoms.calc = calculator

    FIRE(ase.constraints.StrainFilter(atoms, mask=[1, 1, 1, 0, 0, 0]), logfile=None).run(fmax=0.0001)

    # Ec
    Ec = -atoms.get_potential_energy() / len(atoms)

    # a0
    c1, c2, c3 = atoms.get_cell()
    a0 = np.sqrt(np.dot(c1, c1)) / sx

    # C11, C12, C44
    Caffine = calculator.get_birch_coefficients(atoms)
    Cnonaffine = calculator.get_non_affine_contribution_to_elastic_constants(atoms, tol=1e-5)
    C = full_3x3x3x3_to_Voigt_6x6(Caffine + Cnonaffine)
    C11 = C[0, 0] / GPa
    C12 = C[0, 1] / GPa
    C44 = C[3, 3] / GPa
    C110 = full_3x3x3x3_to_Voigt_6x6(Caffine)[0, 0] / GPa
    C120 = full_3x3x3x3_to_Voigt_6x6(Caffine)[0, 1] / GPa
    C440 = full_3x3x3x3_to_Voigt_6x6(Caffine)[3, 3] / GPa
    B = (C11 + 2 * C12) / 3

    # print to screen
    print()
    print(f'=== {name}===')
    l1 = f'          '
    l2 = f'Computed: '
    l3 = f'Reference:'
    for prop in ['Ec', 'a0', 'C11', 'C110', 'C12', 'C120', 'C44', 'C440', 'B']:
        l1 += prop.rjust(11)
        l2 += f'{locals()[prop]:.2f}'.rjust(11)
        if prop in mat:
            l3 += f'{float(mat[prop]):.2f}'.rjust(11)
        else:
            l3 += '---'.rjust(11)
    print(l1)
    print(l2)
    print(l3)

    # actually test properties
    for prop, value in mat.items():
        if prop != 'struct':
            np.testing.assert_allclose(locals()[prop], value, rtol=0.1)
<|endoftext|>


<commit_before>##########################################################################
# Copyright (c) Open Law Library. All rights reserved.                   #
# See ThirdPartyNotices.txt in the project root for license information. #
##########################################################################
import pytest

from pygls import lsp
from pygls.feature_manager import OptionsValidationError, \
    FeatureAlreadyRegisteredError, CommandAlreadyRegisteredError
from tests.fixtures import feature_manager

def test_register_command_validation_error(feature_manager):

    with pytest.raises(OptionsValidationError) as e:
        @feature_manager.command(' \n\t')
        def cmd1():
            pass

def test_register_commands(feature_manager):
    cmd1_name = 'cmd1'
    cmd2_name = 'cmd2'

    @feature_manager.command(cmd1_name)
    def cmd1():
        pass

    @feature_manager.command(cmd2_name)
    def cmd2():
        pass

    reg_commands = feature_manager.commands.keys()

    assert cmd1_name in reg_commands
    assert cmd2_name in reg_commands

    assert feature_manager.commands[cmd1_name] is cmd1
    assert feature_manager.commands[cmd2_name] is cmd2

def test_register_feature_with_options(feature_manager):

    options = {
        'opt1': 1,
        'opt2': 2
    }

    @feature_manager.feature(lsp.COMPLETION, **options)
    def completions():
        pass

    reg_features = feature_manager.features.keys()
    reg_feature_options = feature_manager.feature_options.keys()

    assert lsp.COMPLETION in reg_features
    assert lsp.COMPLETION in reg_feature_options

    assert feature_manager.features[lsp.COMPLETION] is completions
    assert feature_manager.feature_options[lsp.COMPLETION] == options

def test_register_features(feature_manager):

    @feature_manager.feature(lsp.COMPLETION)
    def completions():
        pass

    @feature_manager.feature(lsp.CODE_LENS)
    def code_lens():
        pass

    reg_features = feature_manager.features.keys()

    assert lsp.COMPLETION in reg_features
    assert lsp.CODE_LENS in reg_features

    assert feature_manager.features[lsp.COMPLETION] is completions
    assert feature_manager.features[lsp.CODE_LENS] is code_lens

def test_register_multiple_features_in_same_decorator(feature_manager):

    @feature_manager.feature(lsp.TEXT_DOCUMENT_DID_OPEN,
                             lsp.TEXT_DOCUMENT_DID_CHANGE,
                             lsp.TEXT_DOCUMENT_DID_CLOSE)
    def validate():
        pass

    reg_features = feature_manager.features.keys()

    assert lsp.TEXT_DOCUMENT_DID_OPEN in reg_features
    assert lsp.TEXT_DOCUMENT_DID_CHANGE in reg_features
    assert lsp.TEXT_DOCUMENT_DID_CLOSE in reg_features

    assert feature_manager.features[lsp.TEXT_DOCUMENT_DID_OPEN] is validate
    assert feature_manager.features[lsp.TEXT_DOCUMENT_DID_CHANGE] is validate
    assert feature_manager.features[lsp.TEXT_DOCUMENT_DID_CLOSE] is validate

def test_register_same_command_twice_error(feature_manager):

    with pytest.raises(CommandAlreadyRegisteredError) as e:

        @feature_manager.command('cmd1')
        def cmd1():
            pass

        @feature_manager.command('cmd1')
        def cmd2():
            pass

def test_register_same_feature_twice_error(feature_manager):

    with pytest.raises(FeatureAlreadyRegisteredError) as e:

        @feature_manager.feature(lsp.CODE_ACTION)
        def code_action1():
            pass

        @feature_manager.feature(lsp.CODE_ACTION)
        def code_action2():
            pass
<commit_msg>Fix feature manager tests<commit_after>##########################################################################
# Copyright (c) Open Law Library. All rights reserved.                   #
# See ThirdPartyNotices.txt in the project root for license information. #
##########################################################################
import pytest

from pygls import features as lsp
from pygls.exceptions import CommandAlreadyRegisteredError, \
    FeatureAlreadyRegisteredError, ValidationError
from tests.fixtures import feature_manager

def test_register_command_validation_error(feature_manager):

    with pytest.raises(ValidationError):
        @feature_manager.command(None, ' \n\t')
        def cmd1():
            pass

def test_register_commands(feature_manager):
    cmd1_name = 'cmd1'
    cmd2_name = 'cmd2'

    @feature_manager.command(cmd1_name)
    def cmd1():
        pass

    @feature_manager.command(cmd2_name)
    def cmd2():
        pass

    reg_commands = feature_manager.commands.keys()

    assert cmd1_name in reg_commands
    assert cmd2_name in reg_commands

    assert feature_manager.commands[cmd1_name] is cmd1
    assert feature_manager.commands[cmd2_name] is cmd2

def test_register_feature_with_options(feature_manager):

    options = {
        'opt1': 1,
        'opt2': 2
    }

    @feature_manager.feature(lsp.COMPLETION, **options)
    def completions():
        pass

    reg_features = feature_manager.features.keys()
    reg_feature_options = feature_manager.feature_options.keys()

    assert lsp.COMPLETION in reg_features
    assert lsp.COMPLETION in reg_feature_options

    assert feature_manager.features[lsp.COMPLETION] is completions
    assert feature_manager.feature_options[lsp.COMPLETION] == options

def test_register_features(feature_manager):

    @feature_manager.feature(lsp.COMPLETION)
    def completions():
        pass

    @feature_manager.feature(lsp.CODE_LENS)
    def code_lens():
        pass

    reg_features = feature_manager.features.keys()

    assert lsp.COMPLETION in reg_features
    assert lsp.CODE_LENS in reg_features

    assert feature_manager.features[lsp.COMPLETION] is completions
    assert feature_manager.features[lsp.CODE_LENS] is code_lens

def test_register_multiple_features_in_same_decorator(feature_manager):

    @feature_manager.feature(lsp.TEXT_DOCUMENT_DID_OPEN,
                             lsp.TEXT_DOCUMENT_DID_CHANGE,
                             lsp.TEXT_DOCUMENT_DID_CLOSE)
    def validate():
        pass

    reg_features = feature_manager.features.keys()

    assert lsp.TEXT_DOCUMENT_DID_OPEN in reg_features
    assert lsp.TEXT_DOCUMENT_DID_CHANGE in reg_features
    assert lsp.TEXT_DOCUMENT_DID_CLOSE in reg_features

    assert feature_manager.features[lsp.TEXT_DOCUMENT_DID_OPEN] is validate
    assert feature_manager.features[lsp.TEXT_DOCUMENT_DID_CHANGE] is validate
    assert feature_manager.features[lsp.TEXT_DOCUMENT_DID_CLOSE] is validate

def test_register_same_command_twice_error(feature_manager):

    with pytest.raises(CommandAlreadyRegisteredError) as e:

        @feature_manager.command('cmd1')
        def cmd1():
            pass

        @feature_manager.command('cmd1')
        def cmd2():
            pass

def test_register_same_feature_twice_error(feature_manager):

    with pytest.raises(FeatureAlreadyRegisteredError) as e:

        @feature_manager.feature(lsp.CODE_ACTION)
        def code_action1():
            pass

        @feature_manager.feature(lsp.CODE_ACTION)
        def code_action2():
            pass
<|endoftext|>


<commit_before>#!/usr/bin/env python
# vim:fileencoding=utf-8:noet
from __future__ import (unicode_literals, division, absolute_import, print_function)

import os
import socket
import sys
import codecs
import platform
import re

test_type = sys.argv[1]
test_client = sys.argv[2]
shell = sys.argv[3]
fname = os.path.join('tests', 'shell', '.'.join((shell, test_type, test_client, 'full.log')))
new_fname = os.path.join('tests', 'shell', '.'.join((shell, test_type, test_client, 'log')))
pid_fname = os.path.join('tests', 'shell', '3rd', 'pid')

is_pypy = platform.python_implementation() == 'PyPy'

try:
	with open(pid_fname, 'r') as P:
		pid = P.read().strip()
except IOError:
	pid = None
hostname = socket.gethostname()
user = os.environ['USER']

REFS_RE = re.compile(r'^\[\d+ refs\]\n')
IPYPY_DEANSI_RE = re.compile(r'\033(?:\[(?:\?\d+[lh]|[^a-zA-Z]+[a-ln-zA-Z])|[=>])')

with codecs.open(fname, 'r', encoding='utf-8') as R:
	with codecs.open(new_fname, 'w', encoding='utf-8') as W:
		found_cd = False
		for line in (R if shell != 'fish' else R.read().split('\n')):
			if not found_cd:
				found_cd = ('cd tests/shell/3rd' in line)
				continue
			if 'true is the last line' in line:
				break
			line = line.translate({
				ord('\r'): None
			})
			if REFS_RE.match(line):
				continue
			line = line.replace(hostname, 'HOSTNAME')
			line = line.replace(user, 'USER')
			if pid is not None:
				line = line.replace(pid, 'PID')
			if shell == 'fish':
				res = ''
				try:
					while line.index('\033[0;'):
						start = line.index('\033[0;')
						end = line.index('\033[0m', start)
						res += line[start:end + 4] + '\n'
						line = line[end + 4:]
				except ValueError:
					pass
				line = res
			elif shell == 'tcsh':
				try:
					start = line.index('\033[0;')
					end = line.index(' ', start)
					line = line[start:end] + '\033[0m\n'
				except ValueError:
					line = ''
			elif shell == 'mksh':
				# Output is different in travis: on my machine I see full
				# command, in travis it is truncated just after `true`.
				if line.startswith('[1] + Terminated'):
					line = '[1] + Terminated bash -c ...\n'
			elif shell == 'dash':
				# Position of this line is not stable: it may go both before and
				# after the next line
				if line.startswith('[1] + Terminated'):
					continue
			elif shell == 'ipython' and is_pypy:
				try:
					end_idx = line.rindex('\033[0m')
					try:
						idx = line[:end_idx].rindex('\033[1;1H')
					except ValueError:
						idx = line[:end_idx].rindex('\033[?25h')
					line = line[idx + len('\033[1;1H'):]
				except ValueError:
					pass
				try:
					data_end_idx = line.rindex('\033[1;1H')
					line = line[:data_end_idx] + '\n'
				except ValueError:
					pass
				if line == '\033[1;1H\n':
					continue
				was_empty = line == '\n'
				line = IPYPY_DEANSI_RE.subn('', line)[0]
				if line == '\n' and not was_empty:
					line = ''
			W.write(line)
<commit_msg>When using `rc` remove “read() failed” messages<commit_after>#!/usr/bin/env python
# vim:fileencoding=utf-8:noet
from __future__ import (unicode_literals, division, absolute_import, print_function)

import os
import socket
import sys
import codecs
import platform
import re

test_type = sys.argv[1]
test_client = sys.argv[2]
shell = sys.argv[3]
fname = os.path.join('tests', 'shell', '.'.join((shell, test_type, test_client, 'full.log')))
new_fname = os.path.join('tests', 'shell', '.'.join((shell, test_type, test_client, 'log')))
pid_fname = os.path.join('tests', 'shell', '3rd', 'pid')

is_pypy = platform.python_implementation() == 'PyPy'

try:
	with open(pid_fname, 'r') as P:
		pid = P.read().strip()
except IOError:
	pid = None
hostname = socket.gethostname()
user = os.environ['USER']

REFS_RE = re.compile(r'^\[\d+ refs\]\n')
IPYPY_DEANSI_RE = re.compile(r'\033(?:\[(?:\?\d+[lh]|[^a-zA-Z]+[a-ln-zA-Z])|[=>])')

with codecs.open(fname, 'r', encoding='utf-8') as R:
	with codecs.open(new_fname, 'w', encoding='utf-8') as W:
		found_cd = False
		for line in (R if shell != 'fish' else R.read().split('\n')):
			if not found_cd:
				found_cd = ('cd tests/shell/3rd' in line)
				continue
			if 'true is the last line' in line:
				break
			line = line.translate({
				ord('\r'): None
			})
			if REFS_RE.match(line):
				continue
			line = line.replace(hostname, 'HOSTNAME')
			line = line.replace(user, 'USER')
			if pid is not None:
				line = line.replace(pid, 'PID')
			if shell == 'fish':
				res = ''
				try:
					while line.index('\033[0;'):
						start = line.index('\033[0;')
						end = line.index('\033[0m', start)
						res += line[start:end + 4] + '\n'
						line = line[end + 4:]
				except ValueError:
					pass
				line = res
			elif shell == 'tcsh':
				try:
					start = line.index('\033[0;')
					end = line.index(' ', start)
					line = line[start:end] + '\033[0m\n'
				except ValueError:
					line = ''
			elif shell == 'mksh':
				# Output is different in travis: on my machine I see full
				# command, in travis it is truncated just after `true`.
				if line.startswith('[1] + Terminated'):
					line = '[1] + Terminated bash -c ...\n'
			elif shell == 'dash':
				# Position of this line is not stable: it may go both before and
				# after the next line
				if line.startswith('[1] + Terminated'):
					continue
			elif shell == 'ipython' and is_pypy:
				try:
					end_idx = line.rindex('\033[0m')
					try:
						idx = line[:end_idx].rindex('\033[1;1H')
					except ValueError:
						idx = line[:end_idx].rindex('\033[?25h')
					line = line[idx + len('\033[1;1H'):]
				except ValueError:
					pass
				try:
					data_end_idx = line.rindex('\033[1;1H')
					line = line[:data_end_idx] + '\n'
				except ValueError:
					pass
				if line == '\033[1;1H\n':
					continue
				was_empty = line == '\n'
				line = IPYPY_DEANSI_RE.subn('', line)[0]
				if line == '\n' and not was_empty:
					line = ''
			elif shell == 'rc':
				if line == 'read() failed: Connection reset by peer\n':
					line = ''
			W.write(line)
<|endoftext|>


<commit_before>import pytest
from rml.unitconversion import UnitConversion

def test_identity_conversion():
    id_conversion = UnitConversion([1, 0])
    physics_value = id_conversion.machine_to_physics(4)
    machine_value = id_conversion.physics_to_machine(4)
    assert machine_value == 4
    assert physics_value == 4

def test_linear_conversion():
    linear_conversion = UnitConversion([2, 3])
    physics_value = linear_conversion.machine_to_physics(4)
    machine_value = linear_conversion.physics_to_machine(5)
    assert physics_value == 11
    assert machine_value == 1

def test_quadratic_conversion():
    quadratic_conversion = UnitConversion([1, 2, 3])
    physics_value = quadratic_conversion.machine_to_physics(4)
    assert physics_value == 27
    with pytest.raises(ValueError):
        quadratic_conversion.physics_to_machine(2.5)
<commit_msg>Tests for ppconversion<commit_after>import pytest
from rml.unitconversion import UnitConversion, PPConversion

def test_identity_conversion():
    id_conversion = UnitConversion([1, 0])
    physics_value = id_conversion.machine_to_physics(4)
    machine_value = id_conversion.physics_to_machine(4)
    assert machine_value == 4
    assert physics_value == 4

def test_linear_conversion():
    linear_conversion = UnitConversion([2, 3])
    physics_value = linear_conversion.machine_to_physics(4)
    machine_value = linear_conversion.physics_to_machine(5)
    assert physics_value == 11
    assert machine_value == 1

def test_quadratic_conversion():
    quadratic_conversion = UnitConversion([1, 2, 3])
    physics_value = quadratic_conversion.machine_to_physics(4)
    assert physics_value == 27
    with pytest.raises(ValueError):
        quadratic_conversion.physics_to_machine(2.5)

def test_ppconversion():
    pchip_uc = PPConversion([1, 3], [1, 3])
    assert pchip_uc.machine_to_physics(1) == 1
    assert pchip_uc.machine_to_physics(2) == 2
    assert pchip_uc.machine_to_physics(3) == 3
<|endoftext|>


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

from fabric.api import *
import json
import pytest
import time
from common import *
from common_setup import *
from helpers import Helpers
from MenderAPI import adm, deploy, image, inv
from mendertesting import MenderTesting

@pytest.mark.usefixtures("standard_setup_one_client_bootstrapped")
class TestInventory(MenderTesting):

    @MenderTesting.fast
    def test_inventory(self):
        """Test that device reports inventory after having bootstrapped."""

        attempts = 3

        while True:
            attempts = attempts - 1
            try:
                inv_json = inv.get_devices()
                adm_json = adm.get_devices()

                adm_ids = [device['id'] for device in adm_json]

                assert(len(inv_json) > 0)

                for device in inv_json:
                    try:
                        # Check that admission and inventory agree.
                        assert(device['id'] in adm_ids)

                        attrs = device['attributes']

                        # Check individual attributes.
                        assert(json.loads('{"name": "network_interfaces", "value": "eth0"}') in attrs)
                        assert(json.loads('{"name": "hostname", "value": "vexpress-qemu"}') in attrs)
                        assert(json.loads('{"name": "device_type", "value": "vexpress-qemu"}') in attrs)

                        # Check that all known keys are present.
                        keys = [attr['name'] for attr in attrs]
                        expected_keys = [
                            "hostname",
                            "network_interfaces",
                            "cpu_model",
                            "mem_total",
                            "device_type",
                            "ipv4_eth0",
                            "mac_eth0",
                            "mender_client_version",
                            "artifact_name",
                            "kernel"
                        ]
                        assert(sorted(keys) == sorted(expected_keys))

                    except:
                        print("Exception caught, 'device' json: ", device)
                        raise
                break

            except:
                # This may pass only after the client has had some time to
                # report.
                if attempts > 0:
                    time.sleep(5)
                    continue
                else:
                    raise
<commit_msg>Fix the name of the `mem_total` inventory parameter in tests.<commit_after>#!/usr/bin/python
# Copyright 2016 Mender Software AS
#
#    Licensed under the Apache License, Version 2.0 (the "License");
#    you may not use this file except in compliance with the License.
#    You may obtain a copy of the License at
#
#        https://www.apache.org/licenses/LICENSE-2.0
#
#    Unless required by applicable law or agreed to in writing, software
#    distributed under the License is distributed on an "AS IS" BASIS,
#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#    See the License for the specific language governing permissions and
#    limitations under the License.

from fabric.api import *
import json
import pytest
import time
from common import *
from common_setup import *
from helpers import Helpers
from MenderAPI import adm, deploy, image, inv
from mendertesting import MenderTesting

@pytest.mark.usefixtures("standard_setup_one_client_bootstrapped")
class TestInventory(MenderTesting):

    @MenderTesting.fast
    def test_inventory(self):
        """Test that device reports inventory after having bootstrapped."""

        attempts = 3

        while True:
            attempts = attempts - 1
            try:
                inv_json = inv.get_devices()
                adm_json = adm.get_devices()

                adm_ids = [device['id'] for device in adm_json]

                assert(len(inv_json) > 0)

                for device in inv_json:
                    try:
                        # Check that admission and inventory agree.
                        assert(device['id'] in adm_ids)

                        attrs = device['attributes']

                        # Check individual attributes.
                        assert(json.loads('{"name": "network_interfaces", "value": "eth0"}') in attrs)
                        assert(json.loads('{"name": "hostname", "value": "vexpress-qemu"}') in attrs)
                        assert(json.loads('{"name": "device_type", "value": "vexpress-qemu"}') in attrs)

                        # Check that all known keys are present.
                        keys = [attr['name'] for attr in attrs]
                        expected_keys = [
                            "hostname",
                            "network_interfaces",
                            "cpu_model",
                            "mem_total_kB",
                            "device_type",
                            "ipv4_eth0",
                            "mac_eth0",
                            "mender_client_version",
                            "artifact_name",
                            "kernel"
                        ]
                        assert(sorted(keys) == sorted(expected_keys))

                    except:
                        print("Exception caught, 'device' json: ", device)
                        raise
                break

            except:
                # This may pass only after the client has had some time to
                # report.
                if attempts > 0:
                    time.sleep(5)
                    continue
                else:
                    raise
<|endoftext|>


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

# Copyright (c) 2002-2020 "Neo4j,"
# Neo4j Sweden AB [http://neo4j.com]
#
# This file is part of Neo4j.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from unittest import TestCase

from neo4j import GraphDatabase
from neo4j.addressing import Address

class RoutingTableParseAddressTestCase(TestCase):

    def test_should_parse_ipv4_address_and_port(self):
        parsed = Address.parse("127.0.0.1:7687")
        self.assertEqual(parsed, ("127.0.0.1", 7687))

    def test_should_parse_ipv6_address_and_port(self):
        parsed = Address.parse("[::1]:7687")
        self.assertEqual(parsed, ("::1", 7687, 0, 0))

    def test_should_parse_host_name_and_port(self):
        parsed = Address.parse("localhost:7687")
        self.assertEqual(parsed, ("localhost", 7687))

    def verify_routing_context(self, expected, query):
        context = GraphDatabase._parse_routing_context(query)
        self.assertEqual(context, expected)

    def test_parse_routing_context(self):
        self.verify_routing_context({"name": "molly", "color": "white"}, "name=molly&color=white")
        self.verify_routing_context({"name": "molly", "color": "white"}, "name=molly&color=white")
        self.verify_routing_context({"name": "molly", "color": "white"}, "name=molly&color=white")

    def test_should_error_when_value_missing(self):
        with self.assertRaises(ValueError):
            GraphDatabase._parse_routing_context("name=&color=white")

    def test_should_error_when_key_duplicate(self):
        with self.assertRaises(ValueError):
            GraphDatabase._parse_routing_context("name=molly&name=white")

def test_address_init_with_address_object_returns_same_instance():
    a = Address(("localhost", 7687))
    b = Address(a)
    assert id(a) == id(b)
<commit_msg>Improved Test Coverage of test_addressing.py<commit_after>#!/usr/bin/env python
# -*- encoding: utf-8 -*-

# Copyright (c) 2002-2020 "Neo4j,"
# Neo4j Sweden AB [http://neo4j.com]
#
# This file is part of Neo4j.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import pytest
import unittest.mock as mock
from socket import (
    AF_INET,
    AF_INET6,
)

from neo4j.addressing import (
    Address,
    IPv4Address,
    IPv6Address,
)
from neo4j import GraphDatabase

mock_socket_ipv4 = mock.Mock()
mock_socket_ipv4.getpeername = lambda: ("127.0.0.1", 7687)  # (address, port)

mock_socket_ipv6 = mock.Mock()
mock_socket_ipv6.getpeername = lambda: ("[::1]", 7687, 0, 0)  # (address, port, flow info, scope id)

# python -m pytest tests/unit/test_addressing.py -s

@pytest.mark.parametrize(
    "test_input, expected",
    [
        (("127.0.0.1", 7687), {"family": AF_INET, "host": "127.0.0.1", "port": 7687, "str": "127.0.0.1:7687", "repr": "IPv4Address(('127.0.0.1', 7687))"}),
        (("localhost", 7687), {"family": AF_INET, "host": "localhost", "port": 7687, "str": "localhost:7687", "repr": "IPv4Address(('localhost', 7687))"}),
        ((None, None), {"family": AF_INET, "host": None, "port": None, "str": "None:None", "repr": "IPv4Address((None, None))"}),
        (("::1", 7687), {"family": AF_INET, "host": "::1", "port": 7687, "str": "::1:7687", "repr": "IPv4Address(('::1', 7687))"}),
        (("::1", 7687, 0, 0), {"family": AF_INET6, "host": "::1", "port": 7687, "str": "[::1]:7687", "repr": "IPv6Address(('::1', 7687, 0, 0))"}),
        (("::1", 7687, 1, 2), {"family": AF_INET6, "host": "::1", "port": 7687, "str": "[::1]:7687", "repr": "IPv6Address(('::1', 7687, 1, 2))"}),
        ((None, None, None, None), {"family": AF_INET6, "host": None, "port": None, "str": "[None]:None", "repr": "IPv6Address((None, None, None, None))"}),
        (Address(("127.0.0.1", 7687)), {"family": AF_INET, "host": "127.0.0.1", "port": 7687, "str": "127.0.0.1:7687", "repr": "IPv4Address(('127.0.0.1', 7687))"}),
        (Address(("::1", 7687, 1, 2)), {"family": AF_INET6, "host": "::1", "port": 7687, "str": "[::1]:7687", "repr": "IPv6Address(('::1', 7687, 1, 2))"}),
    ]
)
def test_address_initialization(test_input, expected):
    # python -m pytest tests/unit/test_addressing.py -s -k test_address_initialization
    address = Address(test_input)
    assert address.family == expected["family"]
    assert address.host == expected["host"]
    assert address.port == expected["port"]
    assert str(address) == expected["str"]
    assert repr(address) == expected["repr"]

@pytest.mark.parametrize(
    "test_input",
    [
        Address(("127.0.0.1", 7687)),
        Address(("127.0.0.1", 7687, 1, 2)),
    ]
)
def test_address_init_with_address_object_returns_same_instance(test_input):
    # python -m pytest tests/unit/test_addressing.py -s -k test_address_init_with_address_object_returns_same_instance
    address = Address(test_input)
    assert address is test_input
    assert id(address) == id(test_input)

@pytest.mark.parametrize(
    "test_input, expected",
    [
        (("127.0.0.1",), ValueError),
        (("127.0.0.1", 7687, 0), ValueError),
        (("[::1]", 7687, 0), ValueError),
        (("[::1]", 7687, 0, 0, 0), ValueError),
    ]
)
def test_address_initialization_with_incorrect_input(test_input, expected):
    # python -m pytest tests/unit/test_addressing.py -s -k test_address_initialization_with_incorrect_input
    with pytest.raises(expected):
        address = Address(test_input)

@pytest.mark.parametrize(
    "test_input, expected",
    [
        (mock_socket_ipv4, ("127.0.0.1", 7687)),
        (mock_socket_ipv6, ("[::1]", 7687, 0, 0))
    ]
)
def test_address_from_socket(test_input, expected):
    # python -m pytest tests/unit/test_addressing.py -s -k test_address_from_socket

    address = Address.from_socket(test_input)
    assert address == expected

def test_address_from_socket_with_none():
    # python -m pytest tests/unit/test_addressing.py -s -k test_address_from_socket_with_none
    with pytest.raises(AttributeError):
        address = Address.from_socket(None)

@pytest.mark.parametrize(
    "test_input, expected",
    [
        ("127.0.0.1:7687", ("127.0.0.1", 7687)),
        ("localhost:7687", ("localhost", 7687)),
        (":7687", ("localhost", 7687)),
        (":", ("localhost", 0)),
        ("", ("localhost", 0)),
        (":abcd", ("localhost", "abcd")),
        (" ", (" ", 0)),
    ]
)
def test_address_parse_with_ipv4(test_input, expected):
    # python -m pytest tests/unit/test_addressing.py -s -k test_address_parse_with_ipv4
    parsed = Address.parse(test_input)
    assert parsed == expected

@pytest.mark.parametrize(
    "test_input, expected",
    [
        ("[::1]:7687", ("::1", 7687, 0, 0)),
        ("[::1]:abcd", ("::1", "abcd", 0, 0)),
        ("[::1]:", ("::1", 0, 0, 0)),
        ("[::1]", ("::1", 0, 0, 0)),
    ]
)
def test_address_should_parse_ipv6(test_input, expected):
    # python -m pytest tests/unit/test_addressing.py -s -k test_address_should_parse_ipv6
    parsed = Address.parse(test_input)
    assert parsed == expected

@pytest.mark.parametrize(
    "test_input, expected",
    [
        (None, TypeError),
        (123, TypeError),
        (("127.0.0.1", 7687), TypeError),
        (("[::1]", 7687, 1, 2), TypeError),
        (Address(("127.0.0.1", 7687)), TypeError),
    ]
)
def test_address_parse_with_invalid_input(test_input, expected):
    # python -m pytest tests/unit/test_addressing.py -s -k test_address_parse_with_invalid_input
    with pytest.raises(expected):
        parsed = Address.parse(test_input)

@pytest.mark.parametrize(
    "test_input, expected",
    [
        (("localhost:7687 [::1]:7687",), 2),
        (("localhost:7687", "[::1]:7687"), 2),
        (("localhost:7687 localhost:7688", "[::1]:7687"), 3),
        (("localhost:7687 localhost:7687", "[::1]:7687"), 3),
    ]
)
def test_address_parse_list(test_input, expected):
    # python -m pytest tests/unit/test_addressing.py -s -k test_address_parse_list
    addresses = Address.parse_list(*test_input)
    assert len(addresses) == expected

@pytest.mark.parametrize(
    "test_input, expected",
    [
        (("localhost:7687", None), TypeError),
        (("localhost:7687", 123), TypeError),
        (("localhost:7687", ("127.0.0.1", 7687)), TypeError),
        (("localhost:7687", ("[::1]", 7687, 1, 2)), TypeError),
        (("localhost:7687", Address(("127.0.0.1", 7687))), TypeError),
    ]
)
def test_address_parse_list_with_invalid_input(test_input, expected):
    # python -m pytest tests/unit/test_addressing.py -s -k test_address_parse_list_with_invalid_input
    with pytest.raises(TypeError):
        addresses = Address.parse_list(*test_input)

def test_address_resolve():
    # python -m pytest tests/unit/test_addressing.py -s -k test_address_resolve
    address = Address(("127.0.0.1", 7687))
    resolved = address.resolve()
    assert isinstance(resolved, Address) is False
    assert isinstance(resolved, list) is True
    assert len(resolved) == 1
    assert resolved[0] == IPv4Address(('127.0.0.1', 7687))

def test_address_resolve_with_custom_resolver_none():
    # python -m pytest tests/unit/test_addressing.py -s -k test_address_resolve_with_custom_resolver_none
    address = Address(("127.0.0.1", 7687))
    resolved = address.resolve(resolver=None)
    assert isinstance(resolved, Address) is False
    assert isinstance(resolved, list) is True
    assert len(resolved) == 1
    assert resolved[0] == IPv4Address(('127.0.0.1', 7687))

@pytest.mark.parametrize(
    "test_input, expected",
    [
        (Address(("127.0.0.1", "abcd")), ValueError),
        (Address((None, None)), ValueError),
    ]
)
def test_address_resolve_with_unresolvable_address(test_input, expected):
    # python -m pytest tests/unit/test_addressing.py -s -k test_address_resolve_with_unresolvable_address
    with pytest.raises(expected):
        test_input.resolve(resolver=None)

def test_address_resolve_with_custom_resolver():
    # python -m pytest tests/unit/test_addressing.py -s -k test_address_resolve_with_custom_resolver
    custom_resolver = lambda a: [("127.0.0.1", 7687), ("localhost", 1234)]

    address = Address(("127.0.0.1", 7687))
    resolved = address.resolve(resolver=custom_resolver)
    assert isinstance(resolved, Address) is False
    assert isinstance(resolved, list) is True
    assert len(resolved) == 3
    assert resolved[0] == IPv4Address(('127.0.0.1', 7687))
    assert resolved[1] == IPv6Address(('::1', 1234, 0, 0))
    assert resolved[2] == IPv4Address(('127.0.0.1', 1234))

def test_graphdatabase_parse_routing_context():
    # python -m pytest tests/unit/test_addressing.py -s -k test_graphdatabase_parse_routing_context
    context = GraphDatabase._parse_routing_context(query="name=molly&color=white")
    assert context == {"name": "molly", "color": "white"}

def test_graphdatabase_parse_routing_context_should_error_when_value_missing():
    # python -m pytest tests/unit/test_addressing.py -s -k test_graphdatabase_parse_routing_context_should_error_when_value_missing
    with pytest.raises(ValueError):
        GraphDatabase._parse_routing_context("name=&color=white")

def test_graphdatabase_parse_routing_context_should_error_when_key_duplicate():
    # python -m pytest tests/unit/test_addressing.py -s -k test_graphdatabase_parse_routing_context_should_error_when_key_duplicate
    with pytest.raises(ValueError):
        GraphDatabase._parse_routing_context("name=molly&name=white")
<|endoftext|>