<commit_before>from __future__ import absolute_import
from __future__ import unicode_literals
import collections
from django import forms
from django.forms.fields import MultiValueField, CharField
from django.forms.utils import flatatt
from django.forms.widgets import (
    CheckboxInput,
    Input,
    TextInput,
    MultiWidget,
)
from django.template.loader import render_to_string
from django.utils.encoding import force_text
from django.utils.safestring import mark_safe
import json
from django.utils.translation import ugettext_noop
from dimagi.utils.dates import DateSpan
import six
from six.moves import range

class BootstrapCheckboxInput(CheckboxInput):

    def __init__(self, attrs=None, check_test=bool, inline_label=""):
        super(BootstrapCheckboxInput, self).__init__(attrs, check_test)
        self.inline_label = inline_label

    def render(self, name, value, attrs=None):
        extra_attrs = {'type': 'checkbox', 'name': name}
        extra_attrs.update(self.attrs)
        final_attrs = self.build_attrs(attrs, extra_attrs=extra_attrs)
        try:
            result = self.check_test(value)
        except: # Silently catch exceptions
            result = False
        if result:
            final_attrs['checked'] = 'checked'
        if value not in ('', True, False, None):
            # Only add the 'value' attribute if a value is non-empty.
            final_attrs['value'] = force_text(value)
        return mark_safe('<input%s /> %s' %
                         (flatatt(final_attrs), self.inline_label))

class _Select2Mixin(object):

    class Media(object):
        css = {
            'all': ('select2-3.5.2-legacy/select2.css',)
        }
        js = ('select2-3.5.2-legacy/select2.js',)

    def render(self, name, value, attrs=None, choices=()):
        output = super(_Select2Mixin, self).render(name, value, attrs)
        output += """

        """ % attrs.get('id')
        return mark_safe(output)

class Select2MultipleChoiceWidget(_Select2Mixin, forms.SelectMultiple):
    pass

class _Select2AjaxMixin():
    """
    A Select2 widget that loads its options asynchronously.

    You must use `set_url()` to set the url. This will usually be done in the form's __init__() method.
    The url is not specified in the form class definition because in most cases the url will be dependent on the
    domain of the request.
    """
    def set_url(self, url):
        self.url = url

    def set_initial(self, val):
        self._initial = val

    def _clean_initial(self, val):
        if isinstance(val, collections.Sequence) and not isinstance(val, (str, six.text_type)):
            # if its a tuple or list
            return {"id": val[0], "text": val[1]}
        elif val is None:
            return None
        else:
            # if its a scalar
            return {"id": val, "text": val}

class Select2AjaxV3(_Select2AjaxMixin, forms.TextInput):
    def __init__(self, attrs=None, page_size=20, multiple=False):
        self.page_size = page_size
        self.multiple = multiple
        self._initial = None
        super(Select2AjaxV3, self).__init__(attrs)

    def render(self, name, value, attrs=None):
        attrs.update({
            'class': 'form-control hqwebapp-select2-ajax-v3',
            'data-initial': json.dumps(self._initial if self._initial is not None else self._clean_initial(value)),
            'data-endpoint': self.url,
            'data-page-size': self.page_size,
            'data-multiple': '1' if self.multiple else '0',
        })
        output = super(Select2AjaxV3, self).render(name, value, attrs)
        return mark_safe(output)

class Select2AjaxV4(_Select2AjaxMixin, forms.Select):
    def __init__(self, attrs=None, page_size=20, multiple=False):
        self.page_size = page_size
        self.multiple = multiple
        self._initial = None
        super(Select2AjaxV4, self).__init__(attrs)

    def render(self, name, value, attrs=None):
        attrs.update({
            'class': 'form-control hqwebapp-select2-ajax-v4',
            'data-initial': json.dumps(self._initial if self._initial is not None else self._clean_initial(value)),
            'data-endpoint': self.url,
            'data-page-size': self.page_size,
            'data-multiple': '1' if self.multiple else '0',
        })
        output = super(Select2AjaxV4, self).render(name, value, attrs)
        return mark_safe(output)

class DateRangePickerWidget(Input):
    """
    Extends the standard input widget to render a Date Range Picker Widget.
    Documentation and Demo here: http://www.daterangepicker.com/

    usage:
    apply the following decorator to your view's dispatch method

    @use_daterangepicker
    def dispatch(self, request, *args, **kwargs):
        super(self, MyView).dispatch(request, *args, **kwargs)
    """

    class Range(object):
        LAST_7 = 'last_7_days'
        LAST_MONTH = 'last_month'
        LAST_30_DAYS = 'last_30_days'

    range_labels = {
        Range.LAST_7: ugettext_noop('Last 7 Days'),
        Range.LAST_MONTH: ugettext_noop('Last Month'),
        Range.LAST_30_DAYS: ugettext_noop('Last 30 Days'),
    }
    separator = ugettext_noop(' to ')

    def __init__(self, attrs=None, range_labels=None, separator=None,
                 default_datespan=None):
        self.range_labels = range_labels or self.range_labels
        self.separator = separator or self.separator
        self.default_datespan = default_datespan
        super(DateRangePickerWidget, self).__init__(attrs=attrs)

    def render(self, name, value, attrs=None):
        final_attrs = self.build_attrs(attrs)
        output = super(DateRangePickerWidget, self).render(name, value, attrs)
        # yes, I know inline html in python is gross, but this is what the
        # built in django widgets are doing. :|
        output += """

        """ % {
            'elem_id': final_attrs.get('id'),
            'separator': self.separator,
            'range_labels_json': json.dumps(self.range_labels),
            'startdate': (self.default_datespan.startdate.strftime('%m/%d/%Y')
                          if (isinstance(self.default_datespan, DateSpan)
                              and self.default_datespan.startdate is not None)
                          else ''),
            'enddate': (self.default_datespan.enddate.strftime('%m/%d/%Y')
                        if (isinstance(self.default_datespan, DateSpan)
                            and self.default_datespan.enddate is not None)
                        else ''),
        }
        output = """

        """ + output
        output = '
{}
'.format(output)
        return mark_safe(output)
<commit_msg>Removed Select2MultipleChoiceWidget and _Select2Mixin<commit_after>from __future__ import absolute_import
from __future__ import unicode_literals
import collections
from django import forms
from django.forms.fields import MultiValueField, CharField
from django.forms.utils import flatatt
from django.forms.widgets import (
    CheckboxInput,
    Input,
    TextInput,
    MultiWidget,
)
from django.template.loader import render_to_string
from django.utils.encoding import force_text
from django.utils.safestring import mark_safe
import json
from django.utils.translation import ugettext_noop
from dimagi.utils.dates import DateSpan
import six
from six.moves import range

class BootstrapCheckboxInput(CheckboxInput):

    def __init__(self, attrs=None, check_test=bool, inline_label=""):
        super(BootstrapCheckboxInput, self).__init__(attrs, check_test)
        self.inline_label = inline_label

    def render(self, name, value, attrs=None):
        extra_attrs = {'type': 'checkbox', 'name': name}
        extra_attrs.update(self.attrs)
        final_attrs = self.build_attrs(attrs, extra_attrs=extra_attrs)
        try:
            result = self.check_test(value)
        except: # Silently catch exceptions
            result = False
        if result:
            final_attrs['checked'] = 'checked'
        if value not in ('', True, False, None):
            # Only add the 'value' attribute if a value is non-empty.
            final_attrs['value'] = force_text(value)
        return mark_safe('<input%s /> %s' %
                         (flatatt(final_attrs), self.inline_label))

class _Select2AjaxMixin():
    """
    A Select2 widget that loads its options asynchronously.

    You must use `set_url()` to set the url. This will usually be done in the form's __init__() method.
    The url is not specified in the form class definition because in most cases the url will be dependent on the
    domain of the request.
    """
    def set_url(self, url):
        self.url = url

    def set_initial(self, val):
        self._initial = val

    def _clean_initial(self, val):
        if isinstance(val, collections.Sequence) and not isinstance(val, (str, six.text_type)):
            # if its a tuple or list
            return {"id": val[0], "text": val[1]}
        elif val is None:
            return None
        else:
            # if its a scalar
            return {"id": val, "text": val}

class Select2AjaxV3(_Select2AjaxMixin, forms.TextInput):
    def __init__(self, attrs=None, page_size=20, multiple=False):
        self.page_size = page_size
        self.multiple = multiple
        self._initial = None
        super(Select2AjaxV3, self).__init__(attrs)

    def render(self, name, value, attrs=None):
        attrs.update({
            'class': 'form-control hqwebapp-select2-ajax-v3',
            'data-initial': json.dumps(self._initial if self._initial is not None else self._clean_initial(value)),
            'data-endpoint': self.url,
            'data-page-size': self.page_size,
            'data-multiple': '1' if self.multiple else '0',
        })
        output = super(Select2AjaxV3, self).render(name, value, attrs)
        return mark_safe(output)

class Select2AjaxV4(_Select2AjaxMixin, forms.Select):
    def __init__(self, attrs=None, page_size=20, multiple=False):
        self.page_size = page_size
        self.multiple = multiple
        self._initial = None
        super(Select2AjaxV4, self).__init__(attrs)

    def render(self, name, value, attrs=None):
        attrs.update({
            'class': 'form-control hqwebapp-select2-ajax-v4',
            'data-initial': json.dumps(self._initial if self._initial is not None else self._clean_initial(value)),
            'data-endpoint': self.url,
            'data-page-size': self.page_size,
            'data-multiple': '1' if self.multiple else '0',
        })
        output = super(Select2AjaxV4, self).render(name, value, attrs)
        return mark_safe(output)

class DateRangePickerWidget(Input):
    """
    Extends the standard input widget to render a Date Range Picker Widget.
    Documentation and Demo here: http://www.daterangepicker.com/

    usage:
    apply the following decorator to your view's dispatch method

    @use_daterangepicker
    def dispatch(self, request, *args, **kwargs):
        super(self, MyView).dispatch(request, *args, **kwargs)
    """

    class Range(object):
        LAST_7 = 'last_7_days'
        LAST_MONTH = 'last_month'
        LAST_30_DAYS = 'last_30_days'

    range_labels = {
        Range.LAST_7: ugettext_noop('Last 7 Days'),
        Range.LAST_MONTH: ugettext_noop('Last Month'),
        Range.LAST_30_DAYS: ugettext_noop('Last 30 Days'),
    }
    separator = ugettext_noop(' to ')

    def __init__(self, attrs=None, range_labels=None, separator=None,
                 default_datespan=None):
        self.range_labels = range_labels or self.range_labels
        self.separator = separator or self.separator
        self.default_datespan = default_datespan
        super(DateRangePickerWidget, self).__init__(attrs=attrs)

    def render(self, name, value, attrs=None):
        final_attrs = self.build_attrs(attrs)
        output = super(DateRangePickerWidget, self).render(name, value, attrs)
        # yes, I know inline html in python is gross, but this is what the
        # built in django widgets are doing. :|
        output += """

        """ % {
            'elem_id': final_attrs.get('id'),
            'separator': self.separator,
            'range_labels_json': json.dumps(self.range_labels),
            'startdate': (self.default_datespan.startdate.strftime('%m/%d/%Y')
                          if (isinstance(self.default_datespan, DateSpan)
                              and self.default_datespan.startdate is not None)
                          else ''),
            'enddate': (self.default_datespan.enddate.strftime('%m/%d/%Y')
                        if (isinstance(self.default_datespan, DateSpan)
                            and self.default_datespan.enddate is not None)
                        else ''),
        }
        output = """

        """ + output
        output = '
{}
'.format(output)
        return mark_safe(output)
<|endoftext|>


<commit_before>import pytest

import matchzoo as mz

@pytest.mark.slow
def test_load_data():
    train_data = mz.datasets.wiki_qa.load_data('train', task='ranking')
    assert len(train_data) == 20360
    train_data, _ = mz.datasets.wiki_qa.load_data('train',
                                                  task='classification',
                                                  return_classes=True)
    assert len(train_data) == 20360

    dev_data = mz.datasets.wiki_qa.load_data('dev', task='ranking',
                                             filtered=False)
    assert len(dev_data) == 2733
    dev_data, tag = mz.datasets.wiki_qa.load_data('dev', task='classification',
                                                  filtered=True,
                                                  return_classes=True)
    assert len(dev_data) == 1126
    assert tag == [False, True]

    test_data = mz.datasets.wiki_qa.load_data('test', task='ranking',
                                              filtered=False)
    assert len(test_data) == 6165
    test_data, tag = mz.datasets.wiki_qa.load_data('test',
                                                   task='classification',
                                                   filtered=True,
                                                   return_classes=True)
    assert len(test_data) == 2341
    assert tag == [False, True]

@pytest.mark.slow
def test_load_snli():
    train_data, classes = mz.datasets.snli.load_data('train',
                                                     'classification',
                                                     return_classes=True)
    assert len(train_data) == 550152
    x, y = train_data.unpack()
    assert len(x['text_left']) == 550152
    assert len(x['text_right']) == 550152
    assert y.shape == (550152, 4)
    assert classes == ['entailment', 'contradiction', 'neutral', '-']
    dev_data, classes = mz.datasets.snli.load_data('dev', 'classification',
                                                   return_classes=True)
    assert len(dev_data) == 10000
    assert classes == ['entailment', 'contradiction', 'neutral', '-']
    test_data, classes = mz.datasets.snli.load_data('test', 'classification',
                                                    return_classes=True)
    assert len(test_data) == 10000
    assert classes == ['entailment', 'contradiction', 'neutral', '-']

    train_data = mz.datasets.snli.load_data('train', 'ranking')
    x, y = train_data.unpack()
    assert len(x['text_left']) == 550152
    assert len(x['text_right']) == 550152
    assert y.shape == (550152, 1)

@pytest.mark.slow
def test_load_quora_qp():
    train_data = mz.datasets.quora_qp.load_data(task='classification')
    assert len(train_data) == 363177
    x, y = train_data.unpack()
    assert len(x['text_left']) == 363177
    assert len(x['text_right']) == 363177
    assert y.shape == (363177, 2)

    dev_data, tag = mz.datasets.quora_qp.load_data(
        'dev',
        task='classification',
        return_classes=True)
    assert tag == [False, True]
    assert len(dev_data) == 40371

    test_data = mz.datasets.quora_qp.load_data('test')
    assert len(test_data) == 390965

    train_data = mz.datasets.quora_qp.load_data('train', 'ranking')
    x, y = train_data.unpack()
    assert y.shape == (363177, 1)

<commit_msg>#649 fix memory error in test<commit_after>import pytest

import matchzoo as mz

@pytest.mark.slow
def test_load_data():
    train_data = mz.datasets.wiki_qa.load_data('train', task='ranking')
    assert len(train_data) == 20360
    train_data, _ = mz.datasets.wiki_qa.load_data('train',
                                                  task='classification',
                                                  return_classes=True)
    assert len(train_data) == 20360

    dev_data = mz.datasets.wiki_qa.load_data('dev', task='ranking',
                                             filtered=False)
    assert len(dev_data) == 2733
    dev_data, tag = mz.datasets.wiki_qa.load_data('dev', task='classification',
                                                  filtered=True,
                                                  return_classes=True)
    assert len(dev_data) == 1126
    assert tag == [False, True]

    test_data = mz.datasets.wiki_qa.load_data('test', task='ranking',
                                              filtered=False)
    assert len(test_data) == 6165
    test_data, tag = mz.datasets.wiki_qa.load_data('test',
                                                   task='classification',
                                                   filtered=True,
                                                   return_classes=True)
    assert len(test_data) == 2341
    assert tag == [False, True]

@pytest.mark.slow
def test_load_snli():
    train_data, classes = mz.datasets.snli.load_data('train',
                                                     'classification',
                                                     return_classes=True)
    assert len(train_data) == 550152
    x, y = train_data.unpack()
    assert len(x['text_left']) == 550152
    assert len(x['text_right']) == 550152
    assert y.shape == (550152, 4)
    assert classes == ['entailment', 'contradiction', 'neutral', '-']
    dev_data, classes = mz.datasets.snli.load_data('dev', 'classification',
                                                   return_classes=True)
    assert len(dev_data) == 10000
    assert classes == ['entailment', 'contradiction', 'neutral', '-']
    test_data, classes = mz.datasets.snli.load_data('test', 'classification',
                                                    return_classes=True)
    assert len(test_data) == 10000
    assert classes == ['entailment', 'contradiction', 'neutral', '-']

    train_data = mz.datasets.snli.load_data('train', 'ranking')
    x, y = train_data.unpack()
    assert len(x['text_left']) == 550152
    assert len(x['text_right']) == 550152
    assert y.shape == (550152, 1)

@pytest.mark.slow
def test_load_quora_qp():
    train_data = mz.datasets.quora_qp.load_data(task='classification')
    assert len(train_data) == 363177

    dev_data, tag = mz.datasets.quora_qp.load_data(
        'dev',
        task='classification',
        return_classes=True)
    assert tag == [False, True]
    assert len(dev_data) == 40371
    x, y = dev_data.unpack()
    assert len(x['text_left']) == 40371
    assert len(x['text_right']) == 40371
    assert y.shape == (40371, 2)

    test_data = mz.datasets.quora_qp.load_data('test')
    assert len(test_data) == 390965

    train_data = mz.datasets.quora_qp.load_data('train', 'ranking')
    x, y = train_data.unpack()
    assert y.shape == (363177, 1)

<|endoftext|>


<commit_before>#!/usr/bin/python
# (c) 2018 Jim Hawkins. MIT licensed, see https://opensource.org/licenses/MIT
# Part of Blender Driver, see https://github.com/sjjhsjjh/blender-driver
"""Path Store REST module.

Cannot be run as a program, sorry."""
# Exit if run other than as a module.
if __name__ == '__main__':
    print(__doc__)
    raise SystemExit(1)

# Standard library imports, in alphabetic order.
#
# Module for enum type.
# https://docs.python.org/3.5/library/enum.html
from enum import Enum
#
# Module for levelled logging messages.
# Tutorial is here: https://docs.python.org/3.5/howto/logging.html
# Reference is here: https://docs.python.org/3.5/library/logging.html
from logging import DEBUG, INFO, WARNING, ERROR, log
#
# Local imports.
#
# Path Store module.
try:
    import path_store.pathstore
    pathstore = path_store.pathstore
except ImportError:
    import pathstore

from path_store.animation import Animation
from path_store.blender_game_engine.gameobjectcollection import \
    GameObjectDict, GameObjectList

class RestMethod(Enum):
    DELETE = 1
    GET    = 2
    PATCH  = 3
    POST   = 4
    PUT    = 5

def _generic_value(value):
    # The required test here is: can the value can be serialised into JSON?
    # That could be determined by attempting to serialise, for example by
    # calling json.dumps(value). It seems expensive to process the
    # serialisation, and then discard the result. Instead, the code just
    # checks the type of the value.
    if type(value) in (dict, list, tuple, str, int, float):
        return value
    if value is True or value is False or value is None:
        return value
    # Otherwise, assume it is a class instance and return an empty
    # dictionary.
    return {}

class RestInterface(object):
    """Class for a RESTful interface onto a principal object, implemented by
    Path Store.
    """
    @property
    def principal(self):
        return self._principal

    def get_generic(self, path=None):
        def populate(pointUnused, pathUnused, resultsUnused, second):
            return True, second

        if self.principal is not None:
            self._generic = pathstore.walk(
                self._generic, populate, path, second=self.principal)

        return pathstore.get(self._generic, path)

    def point_maker(self, path, index, point):
        """Default point_maker, which can be overridden so that a subclass can
        have custom points in the path store.
        """
        return pathstore.default_point_maker(path, index, point)

    def rest_patch(self, value, path=None):
        self._principal = pathstore.merge(
            self._principal, value, path, point_maker=self.point_maker)

    def rest_put(self, value, path=None):
        self._principal = pathstore.replace(
            self._principal, value, path, point_maker=self.point_maker)
        self._generic = pathstore.replace(
            self._generic, _generic_value(value), path)

    def rest_get(self, path=None):
        self._generic = pathstore.merge(self._generic, None, path)
        return pathstore.get(self.principal, path)

    def rest_walk(self, editor, path=None, results=None):
        return pathstore.walk(self.principal, editor, path, results)

    def rest_delete(self, path):
        pathstore.delete(self._generic, path)
        return pathstore.delete(self.principal, path)

    def __init__(self):
        self._principal = None
        self._generic = None

class PathAnimation(Animation):

    @property
    def store(self):
        return self._store
    @store.setter
    def store(self, store):
        self._store = store

    @property
    def valuePath(self):
        return self._valuePath
    @valuePath.setter
    def valuePath(self, valuePath):
        self._valuePath = valuePath

    @property
    def subjectPath(self):
        return self._subjectPath
    @subjectPath.setter
    def subjectPath(self, subjectPath):
        self._subjectPath = subjectPath

    @property
    def subject(self):
        return self._subject

    # Override the setter for startTime to get the startValue.
    def _startTimeSetter(self, startTime):
        self.startValue = pathstore.get(self.store, self.valuePath)
        if self.subjectPath is not None:
            self._subject = pathstore.get(self.store, self.subjectPath)
            #
            # Next line will switch off physics.
            self._subject.beingAnimated = True
        Animation.startTime.fset(self, startTime)
    startTime = property(Animation.startTime.fget, _startTimeSetter)

    # Override the setter for nowTime to apply the animation.
    def _nowTimeSetter(self, nowTime):
        Animation.nowTime.fset(self, nowTime)
        pathstore.replace(self.store, self.get_value(), self.valuePath)
    nowTime = property(Animation.nowTime.fget, _nowTimeSetter)

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self._store = None
        self._valuePath = None
        self._subjectPath = None
        self._subject = None

    # It could be handy to cache the parent of the animated point, in order to
    # minimise the number of path descents. However, it might be the case that
    # an object in the path has been replaced in between iterations of the
    # animation. That would stymie caching.

class AnimatedRestInterface(RestInterface):
    """RestInterface with the following items at the top level.

    |
    +-- 'animations'
    |   |
    |   +-- STRING
    |       |
    |       +-- STRING or NUMBER
    |           Individual animation.
    |
    +-- 'root' Conventional item under which all the principal data sits.
        |
        +-- 'gameObjects' GameObjectList or GameObjectDict
            |
            +-- STRING or NUMBER
                Individual game objects.
    """

    @property
    def levels(self):
        return self._levels
    @levels.setter
    def levels(self, levels):
        self._levels = levels

    # Override
    def point_maker(self, path, index, point):
        log(DEBUG, "({}, {}, {}) AnimatedRestInterface", path, index, point)
        #
        # Next line has index == 3, which is one more than the level at which
        # the animation object is to be created. The index < 3 levels can get a
        # None in order to build the array or dictionary.
        if index == 3 and path[0] == 'animations':
            if not isinstance(point, PathAnimation):
                point = PathAnimation()
            point.store = self.principal
            return point

        # if path[0] == self._gameObjectPath[0] and index == 3:
        #     if not isinstance(point, self.GameObject):
        #         point = self.GameObject()

        # Next code checks all the following conditions.
        #
        # -   We are creating a point for the root of the game object tree.
        # -   We know what type of path specifiers will be used at the next
        #     level down: strings or numbers.
        #
        # It is intended to do the quickest checks first.
        depth = self._gameObjectPathLen + self.levels
        if index == depth:
            try:
                pointType = (GameObjectDict if isinstance(path[depth], str)
                             else GameObjectList)
                if isinstance(point, pointType):
                    pointType = None
            except IndexError:
                pointType = None
            if pointType is not None:
                for checkIndex, checkPath in enumerate(self._gameObjectPath):
                    if path[checkIndex] != checkPath:
                        pointType = None
                        break
            if pointType is not None:
                point = pointType()
            # Don't return here, so that the super point_maker can populate the
            # collection with None placeholders if necessary.

        return super().point_maker(path, index, point)

    # Empty class for results of walk().
    class WalkResults:
        pass

    def _process_completed_animations(self, completions):
        for path, completed in completions:
            #
            # Replace completed animation objects with None in the path store,
            # for optimisation.
            self.rest_put(None, path)
            #
            # Check if there are still other animations going on for the same
            # subject.
            #
            # Check that there even is a subject.
            subject = completed.subject
            if subject is None:
                continue
            #
            # There is a subject. The code will walk the animations to see if
            # there are any more for the same subject. Whatever is discovered
            # will be set in a results object. (The other attributes of the walk
            # results object will still be set from the set_now_times first
            # walk.)
            self._walkResults.still = False
            self._walkResults.subject = subject
            #
            # Checking subroutine that can be passed to walk().
            def check(point, path, results):
                if point is None:
                    return
                if point.subject is results.subject and not point.complete:
                    results.still = True
                    raise StopIteration
            self.rest_walk(check, self._animationPath, self._walkResults)
            #
            # If there are no other animations: restore physics to the subject
            # and reset its rotation overrides.
            if not self._walkResults.still:
                subject.beingAnimated = False

    def set_now_times(self, nowTime):
        '''\
        Applies nowTime to everything under the 'animations' path. Returns a
        tuple of:

        -   Boolean for whether there were any completions this time.
        -   A copy of the animation path store structure with either None,
            "Complete", or "Incomplete" at each node.
        '''
        #
        # The code will walk the animations store twice. First to set the now
        # time, second to remove any completed animations. The walk results
        # object is used to collect the outcome.
        #
        # `completions` will be a list of tuples representing animations that
        # completed due to setting the now time. In each tuple:
        #
        # -   First element is the path, as a list.
        # -   Second element is the Animation instance.
        self._walkResults.completions = []
        #
        # `completionsLog` will be a copy of the animation path store structure
        # with either None, "Complete", or "Incomplete" at each node.
        self._walkResults.completionsLog = None
        #
        self._walkResults.anyCompletions = False
        #
        # Checking subroutine that will be passed to walk().
        def set_now(point, path, results):
            if point is not None and not point.complete:
                # Setting nowTime in a PathAnimation has the side effect of
                # applying the animation, which could have the further side
                # effect of completing the animation.
                point.nowTime = nowTime
                if point.complete:
                    results.anyCompletions = True
                    results.completions.append((path[:], point))
            logValue = None if point is None else (
                "Complete" if point.complete else "Incomplete")
            results.completionsLog = pathstore.merge(
                results.completionsLog, logValue, path)
        self.rest_walk(set_now, self._animationPath, self._walkResults)
        #
        # In theory, the processing in the following could be done in the
        # previous walk. However, it uses walk() to check for other animations
        # of the same subject, and it seemed a bit hazardous to kick off other
        # walks within a walk. Anyway, this is the second walk.
        self._process_completed_animations(self._walkResults.completions)

        return (
            self._walkResults.anyCompletions, self._walkResults.completionsLog)

    @property
    def animationPath(self):
        return self._animationPath

    # No point having a class here actually because a GameObject can only be
    # constructed with a bge.types.KX_GameObject instance.
    #
    # @property def GameObject(self):
    #     return self._GameObject
    # @GameObject.setter
    # def GameObject(self, GameObject):
    #     self._GameObject = GameObject

    @property
    def gameObjectPath(self):
        return self._gameObjectPath

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        # self._GameObject = None
        self._levels = 0

        self._walkResults = self.WalkResults()
        #
        # Set and populate conventional paths.
        self._animationPath = ('animations',)
        self._gameObjectPath = ('root', 'gameObjects')
        self._gameObjectPathLen = len(self._gameObjectPath)
        for path in (self.animationPath, ): #self.gameObjectPath):
            self.rest_put(None, path)

# Do:
#
# -   restGetCache that contains only data that has been accessed through the
#     RestInterface. But have an API to load the cache maybe.

# Import some classes from the Blender mathutils module, so that values of these
# types can be detected by GET. They need to be converted into list()s so that
# they can be JSON dumped.
# from mathutils import Vector, Matrix, Quaternion

<commit_msg>Changed rest_patch to merge into the generic copy.<commit_after>#!/usr/bin/python
# (c) 2018 Jim Hawkins. MIT licensed, see https://opensource.org/licenses/MIT
# Part of Blender Driver, see https://github.com/sjjhsjjh/blender-driver
"""Path Store REST module.

Cannot be run as a program, sorry."""
# Exit if run other than as a module.
if __name__ == '__main__':
    print(__doc__)
    raise SystemExit(1)

# Standard library imports, in alphabetic order.
#
# Module for enum type.
# https://docs.python.org/3.5/library/enum.html
from enum import Enum
#
# Module for levelled logging messages.
# Tutorial is here: https://docs.python.org/3.5/howto/logging.html
# Reference is here: https://docs.python.org/3.5/library/logging.html
from logging import DEBUG, INFO, WARNING, ERROR, log
#
# Local imports.
#
# Path Store module.
try:
    import path_store.pathstore
    pathstore = path_store.pathstore
except ImportError:
    import pathstore

from path_store.animation import Animation
from path_store.blender_game_engine.gameobjectcollection import \
    GameObjectDict, GameObjectList

class RestMethod(Enum):
    DELETE = 1
    GET    = 2
    PATCH  = 3
    POST   = 4
    PUT    = 5

def _generic_value(value):
    # The required test here is: can the value can be serialised into JSON?
    # That could be determined by attempting to serialise, for example by
    # calling json.dumps(value). It seems expensive to process the
    # serialisation, and then discard the result. Instead, the code just
    # checks the type of the value.
    if type(value) in (dict, list, tuple, str, int, float):
        return value
    if value is True or value is False or value is None:
        return value
    # Otherwise, assume it is a class instance and return an empty
    # dictionary.
    return {}

class RestInterface(object):
    """Class for a RESTful interface onto a principal object, implemented by
    Path Store.
    """
    @property
    def principal(self):
        return self._principal

    def get_generic(self, path=None):
        def populate(pointUnused, pathUnused, resultsUnused, second):
            return True, second

        if self.principal is not None:
            self._generic = pathstore.walk(
                self._generic, populate, path, second=self.principal)

        return pathstore.get(self._generic, path)

    def point_maker(self, path, index, point):
        """Default point_maker, which can be overridden so that a subclass can
        have custom points in the path store.
        """
        return pathstore.default_point_maker(path, index, point)

    def rest_patch(self, value, path=None):
        self._principal = pathstore.merge(
            self._principal, value, path, point_maker=self.point_maker)
        self._generic = pathstore.merge(
            self._generic, _generic_value(value), path)

    def rest_put(self, value, path=None):
        self._principal = pathstore.replace(
            self._principal, value, path, point_maker=self.point_maker)
        self._generic = pathstore.replace(
            self._generic, _generic_value(value), path)

    def rest_get(self, path=None):
        self._generic = pathstore.merge(self._generic, None, path)
        return pathstore.get(self.principal, path)

    def rest_walk(self, editor, path=None, results=None):
        return pathstore.walk(self.principal, editor, path, results)

    def rest_delete(self, path):
        pathstore.delete(self._generic, path)
        return pathstore.delete(self.principal, path)

    def __init__(self):
        self._principal = None
        self._generic = None

class PathAnimation(Animation):

    @property
    def store(self):
        return self._store
    @store.setter
    def store(self, store):
        self._store = store

    @property
    def valuePath(self):
        return self._valuePath
    @valuePath.setter
    def valuePath(self, valuePath):
        self._valuePath = valuePath

    @property
    def subjectPath(self):
        return self._subjectPath
    @subjectPath.setter
    def subjectPath(self, subjectPath):
        self._subjectPath = subjectPath

    @property
    def subject(self):
        return self._subject

    # Override the setter for startTime to get the startValue.
    def _startTimeSetter(self, startTime):
        self.startValue = pathstore.get(self.store, self.valuePath)
        if self.subjectPath is not None:
            self._subject = pathstore.get(self.store, self.subjectPath)
            #
            # Next line will switch off physics.
            self._subject.beingAnimated = True
        Animation.startTime.fset(self, startTime)
    startTime = property(Animation.startTime.fget, _startTimeSetter)

    # Override the setter for nowTime to apply the animation.
    def _nowTimeSetter(self, nowTime):
        Animation.nowTime.fset(self, nowTime)
        pathstore.replace(self.store, self.get_value(), self.valuePath)
    nowTime = property(Animation.nowTime.fget, _nowTimeSetter)

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self._store = None
        self._valuePath = None
        self._subjectPath = None
        self._subject = None

    # It could be handy to cache the parent of the animated point, in order to
    # minimise the number of path descents. However, it might be the case that
    # an object in the path has been replaced in between iterations of the
    # animation. That would stymie caching.

class AnimatedRestInterface(RestInterface):
    """RestInterface with the following items at the top level.

    |
    +-- 'animations'
    |   |
    |   +-- STRING
    |       |
    |       +-- STRING or NUMBER
    |           Individual animation.
    |
    +-- 'root' Conventional item under which all the principal data sits.
        |
        +-- 'gameObjects' GameObjectList or GameObjectDict
            |
            +-- STRING or NUMBER
                Individual game objects.
    """

    @property
    def levels(self):
        return self._levels
    @levels.setter
    def levels(self, levels):
        self._levels = levels

    # Override
    def point_maker(self, path, index, point):
        log(DEBUG, "({}, {}, {}) AnimatedRestInterface", path, index, point)
        #
        # Next line has index == 3, which is one more than the level at which
        # the animation object is to be created. The index < 3 levels can get a
        # None in order to build the array or dictionary.
        if index == 3 and path[0] == 'animations':
            if not isinstance(point, PathAnimation):
                point = PathAnimation()
            point.store = self.principal
            return point

        # if path[0] == self._gameObjectPath[0] and index == 3:
        #     if not isinstance(point, self.GameObject):
        #         point = self.GameObject()

        # Next code checks all the following conditions.
        #
        # -   We are creating a point for the root of the game object tree.
        # -   We know what type of path specifiers will be used at the next
        #     level down: strings or numbers.
        #
        # It is intended to do the quickest checks first.
        depth = self._gameObjectPathLen + self.levels
        if index == depth:
            try:
                pointType = (GameObjectDict if isinstance(path[depth], str)
                             else GameObjectList)
                if isinstance(point, pointType):
                    pointType = None
            except IndexError:
                pointType = None
            if pointType is not None:
                for checkIndex, checkPath in enumerate(self._gameObjectPath):
                    if path[checkIndex] != checkPath:
                        pointType = None
                        break
            if pointType is not None:
                point = pointType()
            # Don't return here, so that the super point_maker can populate the
            # collection with None placeholders if necessary.

        return super().point_maker(path, index, point)

    # Empty class for results of walk().
    class WalkResults:
        pass

    def _process_completed_animations(self, completions):
        for path, completed in completions:
            #
            # Replace completed animation objects with None in the path store,
            # for optimisation.
            self.rest_put(None, path)
            #
            # Check if there are still other animations going on for the same
            # subject.
            #
            # Check that there even is a subject.
            subject = completed.subject
            if subject is None:
                continue
            #
            # There is a subject. The code will walk the animations to see if
            # there are any more for the same subject. Whatever is discovered
            # will be set in a results object. (The other attributes of the walk
            # results object will still be set from the set_now_times first
            # walk.)
            self._walkResults.still = False
            self._walkResults.subject = subject
            #
            # Checking subroutine that can be passed to walk().
            def check(point, path, results):
                if point is None:
                    return
                if point.subject is results.subject and not point.complete:
                    results.still = True
                    raise StopIteration
            self.rest_walk(check, self._animationPath, self._walkResults)
            #
            # If there are no other animations: restore physics to the subject
            # and reset its rotation overrides.
            if not self._walkResults.still:
                subject.beingAnimated = False

    def set_now_times(self, nowTime):
        '''\
        Applies nowTime to everything under the 'animations' path. Returns a
        tuple of:

        -   Boolean for whether there were any completions this time.
        -   A copy of the animation path store structure with either None,
            "Complete", or "Incomplete" at each node.
        '''
        #
        # The code will walk the animations store twice. First to set the now
        # time, second to remove any completed animations. The walk results
        # object is used to collect the outcome.
        #
        # `completions` will be a list of tuples representing animations that
        # completed due to setting the now time. In each tuple:
        #
        # -   First element is the path, as a list.
        # -   Second element is the Animation instance.
        self._walkResults.completions = []
        #
        # `completionsLog` will be a copy of the animation path store structure
        # with either None, "Complete", or "Incomplete" at each node.
        self._walkResults.completionsLog = None
        #
        self._walkResults.anyCompletions = False
        #
        # Checking subroutine that will be passed to walk().
        def set_now(point, path, results):
            if point is not None and not point.complete:
                # Setting nowTime in a PathAnimation has the side effect of
                # applying the animation, which could have the further side
                # effect of completing the animation.
                point.nowTime = nowTime
                if point.complete:
                    results.anyCompletions = True
                    results.completions.append((path[:], point))
            logValue = None if point is None else (
                "Complete" if point.complete else "Incomplete")
            results.completionsLog = pathstore.merge(
                results.completionsLog, logValue, path)
        self.rest_walk(set_now, self._animationPath, self._walkResults)
        #
        # In theory, the processing in the following could be done in the
        # previous walk. However, it uses walk() to check for other animations
        # of the same subject, and it seemed a bit hazardous to kick off other
        # walks within a walk. Anyway, this is the second walk.
        self._process_completed_animations(self._walkResults.completions)

        return (
            self._walkResults.anyCompletions, self._walkResults.completionsLog)

    @property
    def animationPath(self):
        return self._animationPath

    # No point having a class here actually because a GameObject can only be
    # constructed with a bge.types.KX_GameObject instance.
    #
    # @property def GameObject(self):
    #     return self._GameObject
    # @GameObject.setter
    # def GameObject(self, GameObject):
    #     self._GameObject = GameObject

    @property
    def gameObjectPath(self):
        return self._gameObjectPath

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        # self._GameObject = None
        self._levels = 0

        self._walkResults = self.WalkResults()
        #
        # Set and populate conventional paths.
        self._animationPath = ('animations',)
        self._gameObjectPath = ('root', 'gameObjects')
        self._gameObjectPathLen = len(self._gameObjectPath)
        for path in (self.animationPath, ): #self.gameObjectPath):
            self.rest_put(None, path)

# Do:
#
# -   restGetCache that contains only data that has been accessed through the
#     RestInterface. But have an API to load the cache maybe.

# Import some classes from the Blender mathutils module, so that values of these
# types can be detected by GET. They need to be converted into list()s so that
# they can be JSON dumped.
# from mathutils import Vector, Matrix, Quaternion

<|endoftext|>


<commit_before>from rest_framework import serializers

from feder.letters.models import Letter, Attachment
from feder.main.utils import get_full_url_for_context

class NestedAttachmentSerializer(serializers.HyperlinkedModelSerializer):
    filename = serializers.SerializerMethodField()
    url = serializers.SerializerMethodField()

    def get_filename(self, obj):
        return obj.filename

    def get_url(self, obj):
        return obj.get_full_url()

    class Meta:
        model = Attachment
        fields = ("url", "filename")

class NestedLetterSerializer(serializers.HyperlinkedModelSerializer):
    author_user = serializers.StringRelatedField()
    mark_spam_by = serializers.StringRelatedField()
    attachments = serializers.SerializerMethodField()
    email_delivery_status = serializers.SerializerMethodField()
    eml = serializers.SerializerMethodField()

    def get_attachments(self, obj):
        return NestedAttachmentSerializer(
            getattr(obj, "attachments", obj.attachment_set), many=True, read_only=True
        ).data

    def get_eml(self, obj):
        if obj.eml:
            return get_full_url_for_context(obj.get_eml_url(), self.context)

    def get_email_delivery_status(self, obj):
        try:
            return obj.emaillog.status
        except Letter.emaillog.RelatedObjectDoesNotExist:
            return "unknown"

    class Meta:
        model = Letter
        fields = (
            "eml",
            "author_institution",
            "author_user",
            "title",
            "body",
            "quote",
            "email",
            "note",
            "is_spam",
            "is_draft",
            "is_incoming",
            "is_outgoing",
            "email_delivery_status",
            "mark_spam_by",
            "mark_spam_at",
            "eml",
            "created",
            "modified",
            "attachments",
        )
<commit_msg>Updated Letter serializer to include html_body and html_quote fields. (#927)<commit_after>from rest_framework import serializers

from feder.letters.models import Letter, Attachment
from feder.main.utils import get_full_url_for_context

class NestedAttachmentSerializer(serializers.HyperlinkedModelSerializer):
    filename = serializers.SerializerMethodField()
    url = serializers.SerializerMethodField()

    def get_filename(self, obj):
        return obj.filename

    def get_url(self, obj):
        return obj.get_full_url()

    class Meta:
        model = Attachment
        fields = ("url", "filename")

class NestedLetterSerializer(serializers.HyperlinkedModelSerializer):
    author_user = serializers.StringRelatedField()
    mark_spam_by = serializers.StringRelatedField()
    attachments = serializers.SerializerMethodField()
    email_delivery_status = serializers.SerializerMethodField()
    eml = serializers.SerializerMethodField()

    def get_attachments(self, obj):
        return NestedAttachmentSerializer(
            getattr(obj, "attachments", obj.attachment_set), many=True, read_only=True
        ).data

    def get_eml(self, obj):
        if obj.eml:
            return get_full_url_for_context(obj.get_eml_url(), self.context)

    def get_email_delivery_status(self, obj):
        try:
            return obj.emaillog.status
        except Letter.emaillog.RelatedObjectDoesNotExist:
            return "unknown"

    class Meta:
        model = Letter
        fields = (
            "eml",
            "author_institution",
            "author_user",
            "title",
            "body",
            "html_body",
            "quote",
            "html_quote",
            "email",
            "note",
            "is_spam",
            "is_draft",
            "is_incoming",
            "is_outgoing",
            "email_delivery_status",
            "mark_spam_by",
            "mark_spam_at",
            "eml",
            "created",
            "modified",
            "attachments",
        )
<|endoftext|>


<commit_before>'''The MIT License (MIT)

Copyright (c) 2014 Killua

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

Description: PyAria2 is a Python 3 module that provides a wrapper class around Aria2's RPC interface. It can be used to build applications that use Aria2 for downloading data.
Author: Killua
Email: killua_hzl@163.com
'''

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

import subprocess
import xmlrpc.client
import os
import time

DEFAULT_HOST = 'localhost'
DEFAULT_PORT = 6800
SERVER_URI_FORMAT = 'http://{}:{:d}/rpc'

class PyAria2(object):
    def __init__(self, host=DEFAULT_HOST, port=DEFAULT_PORT, session=None):
        '''
        PyAria2 constructor.

        host: string, aria2 rpc host, default is 'localhost'
        port: integer, aria2 rpc port, default is 6800
        session: string, aria2 rpc session saving.
        '''
        if not isAria2Installed():
            raise Exception('aria2 is not installed, please install it before.')

        if not isAria2rpcRunning():
            cmd = 'aria2c' \
                  ' --enable-rpc' \
                  ' --rpc-listen-port %d' \
                  ' --continue' \
                  ' --max-concurrent-downloads=20' \
                  ' --max-connection-per-server=10' \
                  ' --rpc-max-request-size=1024M' % port

            if not session is None:
                cmd += ' --input-file=%s' \
                       ' --save-session-interval=60' \
                       ' --save-session=%s' % (session, session)

            subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE)

            count = 0
            while True:
                if isAria2rpcRunning():
                    break
                else:
                    count += 1
                    time.sleep(3)
                if count == 5:
                    raise Exception('aria2 RPC server started failure.')
            print('aria2 RPC server is started.')
        else:
            print('aria2 RPC server is already running.')

        server_uri = SERVER_URI_FORMAT.format(host, port)
        self.server = xmlrpc.client.ServerProxy(server_uri, allow_none=True)

    def addUri(self, uris, options=None, position=None):
        '''
        This method adds new HTTP(S)/FTP/BitTorrent Magnet URI.

        uris: list, list of URIs
        options: dict, additional options
        position: integer, position in download queue

        return: This method returns GID of registered download.
        '''
        return self.server.aria2.addUri(uris, options, position)

    def addTorrent(self, torrent, uris=None, options=None, position=None):
        '''
        This method adds BitTorrent download by uploading ".torrent" file.

        torrent: string, torrent file path
        uris: list, list of webseed URIs
        options: dict, additional options
        position: integer, position in download queue

        return: This method returns GID of registered download.
        '''
        return self.server.aria2.addTorrent(xmlrpc.client.Binary(open(torrent, 'rb').read()), uris, options, position)

    def addMetalink(self, metalink, options=None, position=None):
        '''
        This method adds Metalink download by uploading ".metalink" file.

        metalink: string, metalink file path
        options: dict, additional options
        position: integer, position in download queue

        return: This method returns list of GID of registered download.
        '''
        return self.server.aria2.addMetalink(xmlrpc.client.Binary(open(metalink, 'rb').read()), options, position)

    def remove(self, gid):
        '''
        This method removes the download denoted by gid.

        gid: string, GID.

        return: This method returns GID of removed download.
        '''
        return self.server.aria2.remove(gid)

    def forceRemove(self, gid):
        '''
        This method removes the download denoted by gid.

        gid: string, GID.

        return: This method returns GID of removed download.
        '''
        return self.server.aria2.forceRemove(gid)

    def pause(self, gid):
        '''
        This method pauses the download denoted by gid.

        gid: string, GID.

        return: This method returns GID of paused download.
        '''
        return self.server.aria2.pause(gid)

    def pauseAll(self):
        '''
        This method is equal to calling aria2.pause() for every active/waiting download.

        return: This method returns OK for success.
        '''
        return self.server.aria2.pauseAll()

    def forcePause(self, gid):
        '''
        This method pauses the download denoted by gid.

        gid: string, GID.

        return: This method returns GID of paused download.
        '''
        return self.server.aria2.forcePause(gid)

    def forcePauseAll(self):
        '''
        This method is equal to calling aria2.forcePause() for every active/waiting download.

        return: This method returns OK for success.
        '''
        return self.server.aria2.forcePauseAll()

    def unpause(self, gid):
        '''
        This method changes the status of the download denoted by gid from paused to waiting.

        gid: string, GID.

        return: This method returns GID of unpaused download.
        '''
        return self.server.aria2.unpause(gid)

    def unpauseAll(self):
        '''
        This method is equal to calling aria2.unpause() for every active/waiting download.

        return: This method returns OK for success.
        '''
        return self.server.aria2.unpauseAll()

    def tellStatus(self, gid, keys=None):
        '''
        This method returns download progress of the download denoted by gid.

        gid: string, GID.
        keys: list, keys for method response.

        return: The method response is of type dict and it contains following keys.
        '''
        return self.server.aria2.tellStatus(gid, keys)

    def getUris(self, gid):
        '''
        This method returns URIs used in the download denoted by gid.

        gid: string, GID.

        return: The method response is of type list and its element is of type dict and it contains following keys.
        '''
        return self.server.aria2.getUris(gid)

    def getFiles(self, gid):
        '''
        This method returns file list of the download denoted by gid.

        gid: string, GID.

        return: The method response is of type list and its element is of type dict and it contains following keys.
        '''
        return self.server.aria2.getFiles(gid)

    def getPeers(self, gid):
        '''
        This method returns peer list of the download denoted by gid.

        gid: string, GID.

        return: The method response is of type list and its element is of type dict and it contains following keys.
        '''
        return self.server.aria2.getPeers(gid)

    def getServers(self, gid):
        '''
        This method returns currently connected HTTP(S)/FTP servers of the download denoted by gid.

        gid: string, GID.

        return: The method response is of type list and its element is of type dict and it contains following keys.
        '''
        return self.server.aria2.getServers(gid)

    def tellActive(self, keys=None):
        '''
        This method returns the list of active downloads.

        keys: keys for method response.

        return: The method response is of type list and its element is of type dict and it contains following keys.
        '''
        return self.server.aria2.tellActive(keys)

    def tellWaiting(self, offset, num, keys=None):
        '''
        This method returns the list of waiting download, including paused downloads.

        offset: integer, the offset from the download waiting at the front.
        num: integer, the number of downloads to be returned.
        keys: keys for method response.

        return: The method response is of type list and its element is of type dict and it contains following keys.
        '''
        return self.server.aria2.tellWaiting(offset, num, keys)

    def tellStopped(self, offset, num, keys=None):
        '''
        This method returns the list of stopped download.

        offset: integer, the offset from the download waiting at the front.
        num: integer, the number of downloads to be returned.
        keys: keys for method response.

        return: The method response is of type list and its element is of type dict and it contains following keys.
        '''
        return self.server.aria2.tellStopped(offset, num, keys)

    def changePosition(self, gid, pos, how):
        '''
        This method changes the position of the download denoted by gid.

        gid: string, GID.
        pos: integer, the position relative which to be changed.
        how: string.
             POS_SET, it moves the download to a position relative to the beginning of the queue.
             POS_CUR, it moves the download to a position relative to the current position.
             POS_END, it moves the download to a position relative to the end of the queue.

        return: The response is of type integer and it is the destination position.
        '''
        return self.server.aria2.changePosition(gid, pos, how)

    def changeUri(self, gid, fileIndex, delUris, addUris, position=None):
        '''
        This method removes URIs in delUris from and appends URIs in addUris to download denoted by gid.

        gid: string, GID.
        fileIndex: integer, file to affect (1-based)
        delUris: list, URIs to be removed
        addUris: list, URIs to be added
        position: integer, where URIs are inserted, after URIs have been removed

        return: This method returns a list which contains 2 integers. The first integer is the number of URIs deleted. The second integer is the number of URIs added.
        '''
        return self.server.aria2.changeUri(gid, fileIndex, delUris, addUris, position)

    def getOption(self, gid):
        '''
        This method returns options of the download denoted by gid.

        gid: string, GID.

        return: The response is of type dict.
        '''
        return self.server.aria2.getOption(gid)

    def changeOption(self, gid, options):
        '''
        This method changes options of the download denoted by gid dynamically.

        gid: string, GID.
        options: dict, the options.

        return: This method returns OK for success.
        '''
        return self.server.aria2.changeOption(gid, options)

    def getGlobalOption(self):
        '''
        This method returns global options.

        return: The method response is of type dict.
        '''
        return self.server.aria2.getGlobalOption()

    def changeGlobalOption(self, options):
        '''
        This method changes global options dynamically.

        options: dict, the options.

        return: This method returns OK for success.
        '''
        return self.server.aria2.changeGlobalOption(options)

    def getGlobalStat(self):
        '''
        This method returns global statistics such as overall download and upload speed.

        return: The method response is of type struct and contains following keys.
        '''
        return self.server.aria2.getGlobalStat()

    def purgeDownloadResult(self):
        '''
        This method purges completed/error/removed downloads to free memory.

        return: This method returns OK for success.
        '''
        return self.server.aria2.purgeDownloadResult()

    def removeDownloadResult(self, gid):
        '''
        This method removes completed/error/removed download denoted by gid from memory.

        return: This method returns OK for success.
        '''
        return self.server.aria2.removeDownloadResult(gid)

    def getVersion(self):
        '''
        This method returns version of the program and the list of enabled features.

        return: The method response is of type dict and contains following keys.
        '''
        return self.server.aria2.getVersion()

    def getSessionInfo(self):
        '''
        This method returns session information.

        return: The response is of type dict.
        '''
        return self.server.aria2.getSessionInfo()

    def shutdown(self):
        '''
        This method shutdowns aria2.

        return: This method returns OK for success.
        '''
        return self.server.aria2.shutdown()

    def forceShutdown(self):
        '''
        This method shutdowns aria2.

        return: This method returns OK for success.
        '''
        return self.server.aria2.forceShutdown()

def isAria2Installed():
    for cmdpath in os.environ['PATH'].split(':'):
        if os.path.isdir(cmdpath) and 'aria2c' in os.listdir(cmdpath):
            return True

    return False

def isAria2rpcRunning():
    pgrep_process = subprocess.Popen('pgrep -l aria2', shell=True, stdout=subprocess.PIPE)

    if pgrep_process.stdout.readline() == b'':
        return False
    else:
        return True
<commit_msg>Modify module description.<commit_after>'''The MIT License (MIT)

Copyright (c) 2014 Killua

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

Description: pyaria2 is a Python 3 module that provides a wrapper class around Aria2's RPC interface. It can be used to build applications that use Aria2 for downloading data.
Author: Killua
Email: killua_hzl@163.com
'''

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

import subprocess
import xmlrpc.client
import os
import time

DEFAULT_HOST = 'localhost'
DEFAULT_PORT = 6800
SERVER_URI_FORMAT = 'http://{}:{:d}/rpc'

class PyAria2(object):
    def __init__(self, host=DEFAULT_HOST, port=DEFAULT_PORT, session=None):
        '''
        PyAria2 constructor.

        host: string, aria2 rpc host, default is 'localhost'
        port: integer, aria2 rpc port, default is 6800
        session: string, aria2 rpc session saving.
        '''
        if not isAria2Installed():
            raise Exception('aria2 is not installed, please install it before.')

        if not isAria2rpcRunning():
            cmd = 'aria2c' \
                  ' --enable-rpc' \
                  ' --rpc-listen-port %d' \
                  ' --continue' \
                  ' --max-concurrent-downloads=20' \
                  ' --max-connection-per-server=10' \
                  ' --rpc-max-request-size=1024M' % port

            if not session is None:
                cmd += ' --input-file=%s' \
                       ' --save-session-interval=60' \
                       ' --save-session=%s' % (session, session)

            subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE)

            count = 0
            while True:
                if isAria2rpcRunning():
                    break
                else:
                    count += 1
                    time.sleep(3)
                if count == 5:
                    raise Exception('aria2 RPC server started failure.')
            print('aria2 RPC server is started.')
        else:
            print('aria2 RPC server is already running.')

        server_uri = SERVER_URI_FORMAT.format(host, port)
        self.server = xmlrpc.client.ServerProxy(server_uri, allow_none=True)

    def addUri(self, uris, options=None, position=None):
        '''
        This method adds new HTTP(S)/FTP/BitTorrent Magnet URI.

        uris: list, list of URIs
        options: dict, additional options
        position: integer, position in download queue

        return: This method returns GID of registered download.
        '''
        return self.server.aria2.addUri(uris, options, position)

    def addTorrent(self, torrent, uris=None, options=None, position=None):
        '''
        This method adds BitTorrent download by uploading ".torrent" file.

        torrent: string, torrent file path
        uris: list, list of webseed URIs
        options: dict, additional options
        position: integer, position in download queue

        return: This method returns GID of registered download.
        '''
        return self.server.aria2.addTorrent(xmlrpc.client.Binary(open(torrent, 'rb').read()), uris, options, position)

    def addMetalink(self, metalink, options=None, position=None):
        '''
        This method adds Metalink download by uploading ".metalink" file.

        metalink: string, metalink file path
        options: dict, additional options
        position: integer, position in download queue

        return: This method returns list of GID of registered download.
        '''
        return self.server.aria2.addMetalink(xmlrpc.client.Binary(open(metalink, 'rb').read()), options, position)

    def remove(self, gid):
        '''
        This method removes the download denoted by gid.

        gid: string, GID.

        return: This method returns GID of removed download.
        '''
        return self.server.aria2.remove(gid)

    def forceRemove(self, gid):
        '''
        This method removes the download denoted by gid.

        gid: string, GID.

        return: This method returns GID of removed download.
        '''
        return self.server.aria2.forceRemove(gid)

    def pause(self, gid):
        '''
        This method pauses the download denoted by gid.

        gid: string, GID.

        return: This method returns GID of paused download.
        '''
        return self.server.aria2.pause(gid)

    def pauseAll(self):
        '''
        This method is equal to calling aria2.pause() for every active/waiting download.

        return: This method returns OK for success.
        '''
        return self.server.aria2.pauseAll()

    def forcePause(self, gid):
        '''
        This method pauses the download denoted by gid.

        gid: string, GID.

        return: This method returns GID of paused download.
        '''
        return self.server.aria2.forcePause(gid)

    def forcePauseAll(self):
        '''
        This method is equal to calling aria2.forcePause() for every active/waiting download.

        return: This method returns OK for success.
        '''
        return self.server.aria2.forcePauseAll()

    def unpause(self, gid):
        '''
        This method changes the status of the download denoted by gid from paused to waiting.

        gid: string, GID.

        return: This method returns GID of unpaused download.
        '''
        return self.server.aria2.unpause(gid)

    def unpauseAll(self):
        '''
        This method is equal to calling aria2.unpause() for every active/waiting download.

        return: This method returns OK for success.
        '''
        return self.server.aria2.unpauseAll()

    def tellStatus(self, gid, keys=None):
        '''
        This method returns download progress of the download denoted by gid.

        gid: string, GID.
        keys: list, keys for method response.

        return: The method response is of type dict and it contains following keys.
        '''
        return self.server.aria2.tellStatus(gid, keys)

    def getUris(self, gid):
        '''
        This method returns URIs used in the download denoted by gid.

        gid: string, GID.

        return: The method response is of type list and its element is of type dict and it contains following keys.
        '''
        return self.server.aria2.getUris(gid)

    def getFiles(self, gid):
        '''
        This method returns file list of the download denoted by gid.

        gid: string, GID.

        return: The method response is of type list and its element is of type dict and it contains following keys.
        '''
        return self.server.aria2.getFiles(gid)

    def getPeers(self, gid):
        '''
        This method returns peer list of the download denoted by gid.

        gid: string, GID.

        return: The method response is of type list and its element is of type dict and it contains following keys.
        '''
        return self.server.aria2.getPeers(gid)

    def getServers(self, gid):
        '''
        This method returns currently connected HTTP(S)/FTP servers of the download denoted by gid.

        gid: string, GID.

        return: The method response is of type list and its element is of type dict and it contains following keys.
        '''
        return self.server.aria2.getServers(gid)

    def tellActive(self, keys=None):
        '''
        This method returns the list of active downloads.

        keys: keys for method response.

        return: The method response is of type list and its element is of type dict and it contains following keys.
        '''
        return self.server.aria2.tellActive(keys)

    def tellWaiting(self, offset, num, keys=None):
        '''
        This method returns the list of waiting download, including paused downloads.

        offset: integer, the offset from the download waiting at the front.
        num: integer, the number of downloads to be returned.
        keys: keys for method response.

        return: The method response is of type list and its element is of type dict and it contains following keys.
        '''
        return self.server.aria2.tellWaiting(offset, num, keys)

    def tellStopped(self, offset, num, keys=None):
        '''
        This method returns the list of stopped download.

        offset: integer, the offset from the download waiting at the front.
        num: integer, the number of downloads to be returned.
        keys: keys for method response.

        return: The method response is of type list and its element is of type dict and it contains following keys.
        '''
        return self.server.aria2.tellStopped(offset, num, keys)

    def changePosition(self, gid, pos, how):
        '''
        This method changes the position of the download denoted by gid.

        gid: string, GID.
        pos: integer, the position relative which to be changed.
        how: string.
             POS_SET, it moves the download to a position relative to the beginning of the queue.
             POS_CUR, it moves the download to a position relative to the current position.
             POS_END, it moves the download to a position relative to the end of the queue.

        return: The response is of type integer and it is the destination position.
        '''
        return self.server.aria2.changePosition(gid, pos, how)

    def changeUri(self, gid, fileIndex, delUris, addUris, position=None):
        '''
        This method removes URIs in delUris from and appends URIs in addUris to download denoted by gid.

        gid: string, GID.
        fileIndex: integer, file to affect (1-based)
        delUris: list, URIs to be removed
        addUris: list, URIs to be added
        position: integer, where URIs are inserted, after URIs have been removed

        return: This method returns a list which contains 2 integers. The first integer is the number of URIs deleted. The second integer is the number of URIs added.
        '''
        return self.server.aria2.changeUri(gid, fileIndex, delUris, addUris, position)

    def getOption(self, gid):
        '''
        This method returns options of the download denoted by gid.

        gid: string, GID.

        return: The response is of type dict.
        '''
        return self.server.aria2.getOption(gid)

    def changeOption(self, gid, options):
        '''
        This method changes options of the download denoted by gid dynamically.

        gid: string, GID.
        options: dict, the options.

        return: This method returns OK for success.
        '''
        return self.server.aria2.changeOption(gid, options)

    def getGlobalOption(self):
        '''
        This method returns global options.

        return: The method response is of type dict.
        '''
        return self.server.aria2.getGlobalOption()

    def changeGlobalOption(self, options):
        '''
        This method changes global options dynamically.

        options: dict, the options.

        return: This method returns OK for success.
        '''
        return self.server.aria2.changeGlobalOption(options)

    def getGlobalStat(self):
        '''
        This method returns global statistics such as overall download and upload speed.

        return: The method response is of type struct and contains following keys.
        '''
        return self.server.aria2.getGlobalStat()

    def purgeDownloadResult(self):
        '''
        This method purges completed/error/removed downloads to free memory.

        return: This method returns OK for success.
        '''
        return self.server.aria2.purgeDownloadResult()

    def removeDownloadResult(self, gid):
        '''
        This method removes completed/error/removed download denoted by gid from memory.

        return: This method returns OK for success.
        '''
        return self.server.aria2.removeDownloadResult(gid)

    def getVersion(self):
        '''
        This method returns version of the program and the list of enabled features.

        return: The method response is of type dict and contains following keys.
        '''
        return self.server.aria2.getVersion()

    def getSessionInfo(self):
        '''
        This method returns session information.

        return: The response is of type dict.
        '''
        return self.server.aria2.getSessionInfo()

    def shutdown(self):
        '''
        This method shutdowns aria2.

        return: This method returns OK for success.
        '''
        return self.server.aria2.shutdown()

    def forceShutdown(self):
        '''
        This method shutdowns aria2.

        return: This method returns OK for success.
        '''
        return self.server.aria2.forceShutdown()

def isAria2Installed():
    for cmdpath in os.environ['PATH'].split(':'):
        if os.path.isdir(cmdpath) and 'aria2c' in os.listdir(cmdpath):
            return True

    return False

def isAria2rpcRunning():
    pgrep_process = subprocess.Popen('pgrep -l aria2', shell=True, stdout=subprocess.PIPE)

    if pgrep_process.stdout.readline() == b'':
        return False
    else:
        return True
<|endoftext|>


<commit_before>import py
from iniconfig import IniConfig, ParseError

def pytest_generate_tests(metafunc):
    if 'input' in metafunc.funcargnames:
        for name, (input, expected) in check_tokens.items():
            metafunc.addcall(id=name, funcargs={
                'input': input,
                'expected': expected,
            })
    elif hasattr(metafunc.function, 'multi'):
        kwargs = metafunc.function.multi.kwargs
        names, values = zip(*kwargs.items())
        values = cartesian_product(*values)
        for p in values:
            metafunc.addcall(funcargs=dict(zip(names, p)))

def cartesian_product(L,*lists):
    # copied from http://bit.ly/cyIXjn
    if not lists:
        for x in L:
            yield (x,)
    else:
        for x in L:
            for y in cartesian_product(lists[0],*lists[1:]):
                yield (x,)+y

check_tokens = {
    'section': (
        '[section]',
        [(0, 'section', None, None)]
    ),
    'value': (
        'value = 1',
        [(0, None, 'value', '1')]
    ),
    'value in section': (
        '[section]\nvalue=1',
        [(0, 'section', None, None), (1, 'section', 'value', '1')]
    ),
    'value with continuation': (
        'names =\n Alice\n Bob',
        [(0, None, 'names', 'Alice\nBob')]
    ),
    'value with aligned continuation': (
        'names = Alice\n'
        '        Bob',
        [(0, None, 'names', 'Alice\nBob')]
    ),
    'blank line':(
        '[section]\n\nvalue=1',
        [(0, 'section', None, None), (2, 'section', 'value', '1')]
    ),
    'comment': (
        '# comment',
        []
    ),
    'comment on value': (
        'value = 1 # comment',
        [(0, None, 'value', '1')]
    ),

    'comment on section': (
        '[section] #comment',
        [(0, 'section', None, None)]
    ),

}

def parse(input):
    # only for testing purposes - _parse() does not use state except path
    ini = object.__new__(IniConfig)
    ini.path = "sample"
    return ini._parse(input)

def test_tokenize(input, expected):
    parsed = parse(input)
    assert parsed == expected

def test_ParseError():
    e = ParseError("filename", 0, "hello")
    assert str(e) == "filename:1: hello"

def test_continuation_needs_perceeding_token():
    excinfo = py.test.raises(ParseError, "parse(' Foo')")
    assert excinfo.value.lineno == 0

def test_continuation_cant_be_after_section():
    excinfo = py.test.raises(ParseError, "parse('[section]\\n Foo')")
    assert excinfo.value.lineno == 1

def test_section_cant_be_empty():
    excinfo = py.test.raises(ParseError, "parse('[]')")

@py.test.mark.multi(line=[
    '!!',
    '[uhm',
    'comeon]',
    '[uhm =',
    ])
def test_error_on_weird_lines(line):
    excinfo = py.test.raises(ParseError, parse, line)

def test_iniconfig_from_file(tmpdir):
    path = tmpdir/'test.txt'
    path.write('[metadata]\nname=1')

    config = IniConfig(path=path)
    assert list(config.sections) == ['metadata']
    config = IniConfig(path, "[diff]")
    assert list(config.sections) == ['diff']
    py.test.raises(TypeError, "IniConfig(data=path.read())")

def test_iniconfig_section_first(tmpdir):
    excinfo = py.test.raises(ParseError, """
        IniConfig("x", data='name=1')
    """)
    assert excinfo.value.msg == "expected section, got name 'name'"

def test_iniconig_section_duplicate_fails():
    excinfo = py.test.raises(ParseError, r"""
        IniConfig("x", data='[section]\n[section]')
    """)
    assert 'duplicate section' in str(excinfo.value)

def test_iniconfig_duplicate_key_fails():
    excinfo = py.test.raises(ParseError, r"""
        IniConfig("x", data='[section]\nname = Alice\nname = bob')
    """)

    assert 'duplicate name' in str(excinfo.value)

def test_iniconfig_lineof():
    config = IniConfig("x.ini", data=
        '[section]\n'
        'value = 1\n'
        '[section2]\n'
        '# comment\n'
        'value =2'
    )

    assert config.lineof('missing') is None
    assert config.lineof('section') == 1
    assert config.lineof('section2') == 3
    assert config.lineof('section', 'value') == 2
    assert config.lineof('section2','value') == 5

def test_iniconfig_get_convert():
    config= IniConfig("x", data='[section]\nint = 1\nfloat = 1.1')
    assert config.get('section', 'int') == '1'
    assert config.get('section', 'int', convert=int) == 1

def test_iniconfig_get_missing():
    config= IniConfig("x", data='[section]\nint = 1\nfloat = 1.1')
    assert config.get('section', 'missing', default=1) == 1
    assert config.get('section', 'missing') is None

def test_section_get():
    config = IniConfig("x", data='[section]\nvalue=1')
    section = config['section']
    assert section.get('value', convert=int) == 1
    assert section.get('value', 1) == "1"
    assert section.get('missing', 2) == 2

def test_get_missing_section():
    config = IniConfig("x", data='[section]\nvalue=1')
    py.test.raises(KeyError,'config["other"]')
    config.get_section('missing') #

def test_section_getitem():
    config = IniConfig("x", data='[section]\nvalue=1')

    missing=config.get_section('test')
    py.test.raises(KeyError, 'missing["something"]')

    assert config['section']['value'] == '1'

def test_section_iter():
    config = IniConfig("x", data='[section]\nvalue=1')
    names = list(config['section'])
    assert names == ['value']
    items = list(config['section'].items())
    assert items==[('value', '1')]

def test_config_iter():
    config = IniConfig("x.ini", data='[section]\nvalue=1')
    assert list(config) == ['section']
    for name, section in config.items():
        assert section.name == name

def test_iter_file_order():
    config = IniConfig("x.ini", data="""
[section2] #cpython dict ordered before section
value = 1
value2 = 2 # dict ordered before value
[section]
a = 1
b = 2
""")
    assert list(config) == ['section2', 'section']
    assert list(config['section2']) == ['value', 'value2']
    assert list(config['section']) == ['a', 'b']

<commit_msg>introduce parse_a_error helper to enhance the readability of parser error tests<commit_after>import py
from iniconfig import IniConfig, ParseError

def pytest_generate_tests(metafunc):
    if 'input' in metafunc.funcargnames:
        for name, (input, expected) in check_tokens.items():
            metafunc.addcall(id=name, funcargs={
                'input': input,
                'expected': expected,
            })
    elif hasattr(metafunc.function, 'multi'):
        kwargs = metafunc.function.multi.kwargs
        names, values = zip(*kwargs.items())
        values = cartesian_product(*values)
        for p in values:
            metafunc.addcall(funcargs=dict(zip(names, p)))

def cartesian_product(L,*lists):
    # copied from http://bit.ly/cyIXjn
    if not lists:
        for x in L:
            yield (x,)
    else:
        for x in L:
            for y in cartesian_product(lists[0],*lists[1:]):
                yield (x,)+y

check_tokens = {
    'section': (
        '[section]',
        [(0, 'section', None, None)]
    ),
    'value': (
        'value = 1',
        [(0, None, 'value', '1')]
    ),
    'value in section': (
        '[section]\nvalue=1',
        [(0, 'section', None, None), (1, 'section', 'value', '1')]
    ),
    'value with continuation': (
        'names =\n Alice\n Bob',
        [(0, None, 'names', 'Alice\nBob')]
    ),
    'value with aligned continuation': (
        'names = Alice\n'
        '        Bob',
        [(0, None, 'names', 'Alice\nBob')]
    ),
    'blank line':(
        '[section]\n\nvalue=1',
        [(0, 'section', None, None), (2, 'section', 'value', '1')]
    ),
    'comment': (
        '# comment',
        []
    ),
    'comment on value': (
        'value = 1 # comment',
        [(0, None, 'value', '1')]
    ),

    'comment on section': (
        '[section] #comment',
        [(0, 'section', None, None)]
    ),

}

def parse(input):
    # only for testing purposes - _parse() does not use state except path
    ini = object.__new__(IniConfig)
    ini.path = "sample"
    return ini._parse(input)

def parse_a_error(input):
    return py.test.raises(ParseError, parse, input)

def test_tokenize(input, expected):
    parsed = parse(input)
    assert parsed == expected

def test_ParseError():
    e = ParseError("filename", 0, "hello")
    assert str(e) == "filename:1: hello"

def test_continuation_needs_perceeding_token():
    excinfo = parse_a_error(' Foo')
    assert excinfo.value.lineno == 0

def test_continuation_cant_be_after_section():
    excinfo = parse_a_error('[section]\n Foo')
    assert excinfo.value.lineno == 1

def test_section_cant_be_empty():
    excinfo = parse_a_error('[]')

@py.test.mark.multi(line=[
    '!!',
    '[uhm',
    'comeon]',
    '[uhm =',
    ])
def test_error_on_weird_lines(line):
    parse_a_error(line)

def test_iniconfig_from_file(tmpdir):
    path = tmpdir/'test.txt'
    path.write('[metadata]\nname=1')

    config = IniConfig(path=path)
    assert list(config.sections) == ['metadata']
    config = IniConfig(path, "[diff]")
    assert list(config.sections) == ['diff']
    py.test.raises(TypeError, "IniConfig(data=path.read())")

def test_iniconfig_section_first(tmpdir):
    excinfo = py.test.raises(ParseError, """
        IniConfig("x", data='name=1')
    """)
    assert excinfo.value.msg == "expected section, got name 'name'"

def test_iniconig_section_duplicate_fails():
    excinfo = py.test.raises(ParseError, r"""
        IniConfig("x", data='[section]\n[section]')
    """)
    assert 'duplicate section' in str(excinfo.value)

def test_iniconfig_duplicate_key_fails():
    excinfo = py.test.raises(ParseError, r"""
        IniConfig("x", data='[section]\nname = Alice\nname = bob')
    """)

    assert 'duplicate name' in str(excinfo.value)

def test_iniconfig_lineof():
    config = IniConfig("x.ini", data=
        '[section]\n'
        'value = 1\n'
        '[section2]\n'
        '# comment\n'
        'value =2'
    )

    assert config.lineof('missing') is None
    assert config.lineof('section') == 1
    assert config.lineof('section2') == 3
    assert config.lineof('section', 'value') == 2
    assert config.lineof('section2','value') == 5

def test_iniconfig_get_convert():
    config= IniConfig("x", data='[section]\nint = 1\nfloat = 1.1')
    assert config.get('section', 'int') == '1'
    assert config.get('section', 'int', convert=int) == 1

def test_iniconfig_get_missing():
    config= IniConfig("x", data='[section]\nint = 1\nfloat = 1.1')
    assert config.get('section', 'missing', default=1) == 1
    assert config.get('section', 'missing') is None

def test_section_get():
    config = IniConfig("x", data='[section]\nvalue=1')
    section = config['section']
    assert section.get('value', convert=int) == 1
    assert section.get('value', 1) == "1"
    assert section.get('missing', 2) == 2

def test_get_missing_section():
    config = IniConfig("x", data='[section]\nvalue=1')
    py.test.raises(KeyError,'config["other"]')
    config.get_section('missing') #

def test_section_getitem():
    config = IniConfig("x", data='[section]\nvalue=1')

    missing=config.get_section('test')
    py.test.raises(KeyError, 'missing["something"]')

    assert config['section']['value'] == '1'

def test_section_iter():
    config = IniConfig("x", data='[section]\nvalue=1')
    names = list(config['section'])
    assert names == ['value']
    items = list(config['section'].items())
    assert items==[('value', '1')]

def test_config_iter():
    config = IniConfig("x.ini", data='[section]\nvalue=1')
    assert list(config) == ['section']
    for name, section in config.items():
        assert section.name == name

def test_iter_file_order():
    config = IniConfig("x.ini", data="""
[section2] #cpython dict ordered before section
value = 1
value2 = 2 # dict ordered before value
[section]
a = 1
b = 2
""")
    assert list(config) == ['section2', 'section']
    assert list(config['section2']) == ['value', 'value2']
    assert list(config['section']) == ['a', 'b']

<|endoftext|>


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

try:
    import http.client as httplib
except ImportError:
    import httplib

import socket

from contextlib import contextmanager

@contextmanager
def tcpip4_socket(host, port):
    """Open a TCP/IP4 socket to designated host/port."""
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    try:
        s.connect((host, port))
        yield s
    finally:
        s.shutdown(socket.SHUT_RDWR)
        s.close()

@contextmanager
def http_connection(host, port):
    """Open an HTTP connection to designated host/port."""
    c = httplib.HTTPConnection(host, port)
    try:
       yield c
    finally:
       c.close()

<commit_msg>socket closing fix?<commit_after>#!/usr/bin/env python

try:
    import http.client as httplib
except ImportError:
    import httplib

import socket

from contextlib import contextmanager

@contextmanager
def tcpip4_socket(host, port):
    """Open a TCP/IP4 socket to designated host/port."""
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    try:
        s.connect((host, port))
        yield s
    finally:
        try:
            s.shutdown(socket.SHUT_RDWR)
        except OSError:
            pass
        finally:
            s.close()

@contextmanager
def http_connection(host, port):
    """Open an HTTP connection to designated host/port."""
    c = httplib.HTTPConnection(host, port)
    try:
       yield c
    finally:
       c.close()

<|endoftext|>