<commit_before>"""server_test.py"""
# pylint: disable=missing-docstring,line-too-long

from nose.tools import assert_equal # pylint: disable=no-name-in-module
import unittest
import json

from .app import App
from . import exceptions

class DummyApp(App): #pylint:disable=too-many-public-methods

    def method_only(self):
        pass

    def one_positional(self, string):
        pass

    def two_positionals(self, one, two):
        pass

    def args(self, *args):
        pass

    def kwargs(self, **kwargs):
        pass

    def positionals_with_args(self, one, two, *args):
        pass

    def positionals_with_kwargs(self, one, two, **kwargs):
        pass

    def positionals_with_args_and_kwargs(self, one, two, *args, **kwargs):
        pass

    @staticmethod
    def add(number1, number2):
        """Add two numbers. Takes a list as args."""

        try:
            return number1 + number2

        except TypeError as e:
            raise exceptions.InvalidParams(str(e))

    @staticmethod
    def uppercase(*args):
        """Uppercase a string"""

        try:
            return args[0].upper()

        except KeyError:
            raise exceptions.InvalidParams()

    @staticmethod
    def lookup_surname(**kwargs):
        """Lookup a surname from a firstname"""

        try:
            if kwargs['firstname'] == 'John':
                return 'Smith'

        except KeyError:
            raise exceptions.InvalidParams()

testapp = DummyApp(__name__)

class AppTestCase(unittest.TestCase): #pylint:disable=no-init,multiple-statements,too-many-public-methods
    """To test:
        method_only()
        one_param(string)
        two_param(one, two)
        many_args(*args)
        many_kwargs(**kwargs)
        positional_with_args(one, two, *args)
        positional_with_kwargs(one, two, **kwargs)
        positional_with_args_and_kwargs(one, two, *args, **kwargs)
    """

    def setUp(self):
        testapp.config['TESTING'] = True
        self.app = testapp.test_client()

    def post(self, expected_response, request):

        response = self.app.post(
            '/', headers={'content-type': 'application/json'}, \
            data=json.dumps(request)).data.decode('utf-8') #pylint:disable=maybe-no-member

        if response:
            response = json.loads(response)

        assert_equal(
            expected_response,
            response
        )

    # MethodNotFound
    def test_MethodNotFound(self):
        self.post(
            {'jsonrpc': '2.0', 'error': {'code': -32601, 'message': 'Method not found'}, 'id': 1},
            {'jsonrpc': '2.0', 'method': 'unknown', 'id': 1}
        )

    # InvalidParams - this requires lots of testing because there are many ways
    # the st params can come through

    # method_only

    def test_method_only_ok(self):
        self.post(
            None,
            {"jsonrpc": "2.0", "method": "method_only"}
        )

    def test_method_only_args(self):
        self.post(
            {"jsonrpc": "2.0", "error": {"code": -32602, "message": "method_only() takes 0 positional arguments but 1 was given"}, "id": 1},
            {"jsonrpc": "2.0", "method": "method_only", "params": [1], "id": 1}
        )

    def test_method_only_kwargs(self):
        self.post(
            {"jsonrpc": "2.0", "error": {"code": -32602, "message": "method_only() got an unexpected keyword argument \'foo\'"}, "id": 1},
            {"jsonrpc": "2.0", "method": "method_only", "params": {"foo": "bar"}, "id": 1}
        )

    def test_method_only_both(self):
        self.post(
            {"jsonrpc": "2.0", "error": {"code": -32602, "message": "method_only() got an unexpected keyword argument \'foo\'"}, "id": 1},
            {"jsonrpc": "2.0", "method": "method_only", "params": [1, 2, {"foo": "bar"}], "id": 1}
        )

    # one_positional

    def test_one_positional_ok(self):
        self.post(
            None,
            {"jsonrpc": "2.0", "method": "one_positional", "params": [1]}
        )

    def test_one_positional_no_args(self):
        self.post(
            {"jsonrpc": "2.0", "error": {"code": -32602, "message": "one_positional() missing 1 required positional argument: \'string\'"}, "id": 1},
            {"jsonrpc": "2.0", "method": "one_positional", "id": 1}
        )

    def test_one_positional_two_args(self):
        self.post(
            {"jsonrpc": "2.0", "error": {"code": -32602, "message": "one_positional() takes 1 positional argument but 2 were given"}, "id": 1},
            {"jsonrpc": "2.0", "method": "one_positional", "params": [1, 2], "id": 1}
        )

    def test_one_positional_kwargs(self):
        self.post(
            {"jsonrpc": "2.0", "error": {"code": -32602, "message": "one_positional() got an unexpected keyword argument \'foo\'"}, "id": 1},
            {"jsonrpc": "2.0", "method": "one_positional", "params": {"foo": "bar"}, "id": 1},
        )

    def test_one_positional_both(self):
        self.post(
            {"jsonrpc": "2.0", "error": {"code": -32602, "message": "one_positional() got an unexpected keyword argument \'foo\'"}, "id": 1},
            {"jsonrpc": "2.0", "method": "one_positional", "params": [1, 2, {"foo": "bar"}], "id": 1}
        )

    # two_positionals

    def test_two_positionals_ok(self):
        self.post(
            {'jsonrpc': '2.0', 'result': None, 'id': 1},
            {"jsonrpc": "2.0", "method": "two_positionals", "params": [1, 2], "id": 1}
        )

    def test_two_positionals_no_args(self):
        self.post(
            {"jsonrpc": "2.0", "error": {"code": -32602, "message": "two_positionals() missing 2 required positional arguments: \'one\' and \'two\'"}, "id": 1},
            {"jsonrpc": "2.0", "method": "two_positionals", "id": 1}
        )

    def test_two_positionals_one_arg(self):
        self.post(
            {"jsonrpc": "2.0", "error": {"code": -32602, "message": "two_positionals() missing 1 required positional argument: \'two\'"}, "id": 1},
            {"jsonrpc": "2.0", "method": "two_positionals", "params": [1], "id": 1}
        )

    def test_two_positionals_kwargs(self):
        self.post(
            {"jsonrpc": "2.0", "error": {"code": -32602, "message": "two_positionals() got an unexpected keyword argument \'foo\'"}, "id": 1},
            {"jsonrpc": "2.0", "method": "two_positionals", "params": {"foo": "bar"}, "id": 1}
        )

    def test_two_positionals_both(self):
        self.post(
            {"jsonrpc": "2.0", "error": {"code": -32602, "message": "two_positionals() got an unexpected keyword argument \'foo\'"}, "id": 1},
            {"jsonrpc": "2.0", "method": "two_positionals", "params": [1, {"foo": "bar"}], "id": 1}
        )

    # Test return results

    def test_add_two_numbers(self):
        self.post(
            {'jsonrpc': '2.0', 'result': 3, 'id': 1},
            {"jsonrpc": "2.0", "method": "add", "params": [1, 2], "id": 1}
        )

    def test_uppercase(self):
        self.post(
            {'jsonrpc': '2.0', 'result': 'TEST', 'id': 1},
            {"jsonrpc": "2.0", "method": "uppercase", "params": ["test"], "id": 1}
        )

    def test_lookup_surname(self):
        self.post(
            {'jsonrpc': '2.0', 'result': 'Smith', 'id': 1},
            {"jsonrpc": "2.0", "method": "lookup_surname", "params": {"firstname": "John"}, "id": 1}
        )
<commit_msg>Tests are passing<commit_after>"""server_test.py"""
# pylint: disable=missing-docstring,line-too-long

from nose.tools import assert_equal # pylint: disable=no-name-in-module
import unittest
import json

from .app import App
from . import exceptions

class DummyApp(App): #pylint:disable=too-many-public-methods

    def method_only(self):
        pass

    def one_positional(self, string):
        pass

    def two_positionals(self, one, two):
        pass

    def args(self, *args):
        pass

    def kwargs(self, **kwargs):
        pass

    def positionals_with_args(self, one, two, *args):
        pass

    def positionals_with_kwargs(self, one, two, **kwargs):
        pass

    def positionals_with_args_and_kwargs(self, one, two, *args, **kwargs):
        pass

    @staticmethod
    def add(number1, number2):
        """Add two numbers. Takes a list as args."""

        try:
            return number1 + number2

        except TypeError as e:
            raise exceptions.InvalidParams(str(e))

    @staticmethod
    def uppercase(*args):
        """Uppercase a string"""

        try:
            return args[0].upper()

        except KeyError:
            raise exceptions.InvalidParams()

    @staticmethod
    def lookup_surname(**kwargs):
        """Lookup a surname from a firstname"""

        try:
            if kwargs['firstname'] == 'John':
                return 'Smith'

        except KeyError:
            raise exceptions.InvalidParams()

testapp = DummyApp(__name__)

class AppTestCase(unittest.TestCase): #pylint:disable=no-init,multiple-statements,too-many-public-methods
    """To test:
        method_only()
        one_param(string)
        two_param(one, two)
        many_args(*args)
        many_kwargs(**kwargs)
        positional_with_args(one, two, *args)
        positional_with_kwargs(one, two, **kwargs)
        positional_with_args_and_kwargs(one, two, *args, **kwargs)
    """

    def setUp(self):
        testapp.config['TESTING'] = True
        self.app = testapp.test_client()

    def post(self, expected_response, request):

        response = self.app.post(
            '/', headers={'content-type': 'application/json'}, \
            data=json.dumps(request)).data.decode('utf-8') #pylint:disable=maybe-no-member

        if response:
            response = json.loads(response)

        assert_equal(
            expected_response,
            response
        )

    # MethodNotFound
    def test_MethodNotFound(self):
        self.post(
            {'jsonrpc': '2.0', 'error': {'code': -32601, 'message': 'Method not found'}, 'id': 1},
            {'jsonrpc': '2.0', 'method': 'unknown', 'id': 1}
        )

    # InvalidParams - this requires lots of testing because there are many ways
    # the st params can come through

    # method_only

    def test_method_only_ok(self):
        self.post(
            '',
            {"jsonrpc": "2.0", "method": "method_only"}
        )

    def test_method_only_args(self):
        self.post(
            {"jsonrpc": "2.0", "error": {"code": -32602, "message": "method_only() takes 1 positional argument but 2 were given"}, "id": 1},
            {"jsonrpc": "2.0", "method": "method_only", "params": [1], "id": 1}
        )

    def test_method_only_kwargs(self):
        self.post(
            {"jsonrpc": "2.0", "error": {"code": -32602, "message": "method_only() got an unexpected keyword argument \'foo\'"}, "id": 1},
            {"jsonrpc": "2.0", "method": "method_only", "params": {"foo": "bar"}, "id": 1}
        )

    def test_method_only_both(self):
        self.post(
            {"jsonrpc": "2.0", "error": {"code": -32602, "message": "method_only() got an unexpected keyword argument \'foo\'"}, "id": 1},
            {"jsonrpc": "2.0", "method": "method_only", "params": [1, 2, {"foo": "bar"}], "id": 1}
        )

    # one_positional

    def test_one_positional_ok(self):
        self.post(
            '',
            {"jsonrpc": "2.0", "method": "one_positional", "params": [1]}
        )

    def test_one_positional_no_args(self):
        self.post(
            {"jsonrpc": "2.0", "error": {"code": -32602, "message": "one_positional() missing 1 required positional argument: \'string\'"}, "id": 1},
            {"jsonrpc": "2.0", "method": "one_positional", "id": 1}
        )

    def test_one_positional_two_args(self):
        self.post(
            {"jsonrpc": "2.0", "error": {"code": -32602, "message": "one_positional() takes 2 positional arguments but 3 were given"}, "id": 1},
            {"jsonrpc": "2.0", "method": "one_positional", "params": [1, 2], "id": 1}
        )

    def test_one_positional_kwargs(self):
        self.post(
            {"jsonrpc": "2.0", "error": {"code": -32602, "message": "one_positional() got an unexpected keyword argument \'foo\'"}, "id": 1},
            {"jsonrpc": "2.0", "method": "one_positional", "params": {"foo": "bar"}, "id": 1},
        )

    def test_one_positional_both(self):
        self.post(
            {"jsonrpc": "2.0", "error": {"code": -32602, "message": "one_positional() got an unexpected keyword argument \'foo\'"}, "id": 1},
            {"jsonrpc": "2.0", "method": "one_positional", "params": [1, 2, {"foo": "bar"}], "id": 1}
        )

    # two_positionals

    def test_two_positionals_ok(self):
        self.post(
            {'jsonrpc': '2.0', 'result': None, 'id': 1},
            {"jsonrpc": "2.0", "method": "two_positionals", "params": [1, 2], "id": 1}
        )

    def test_two_positionals_no_args(self):
        self.post(
            {"jsonrpc": "2.0", "error": {"code": -32602, "message": "two_positionals() missing 2 required positional arguments: \'one\' and \'two\'"}, "id": 1},
            {"jsonrpc": "2.0", "method": "two_positionals", "id": 1}
        )

    def test_two_positionals_one_arg(self):
        self.post(
            {"jsonrpc": "2.0", "error": {"code": -32602, "message": "two_positionals() missing 1 required positional argument: \'two\'"}, "id": 1},
            {"jsonrpc": "2.0", "method": "two_positionals", "params": [1], "id": 1}
        )

    def test_two_positionals_kwargs(self):
        self.post(
            {"jsonrpc": "2.0", "error": {"code": -32602, "message": "two_positionals() got an unexpected keyword argument \'foo\'"}, "id": 1},
            {"jsonrpc": "2.0", "method": "two_positionals", "params": {"foo": "bar"}, "id": 1}
        )

    def test_two_positionals_both(self):
        self.post(
            {"jsonrpc": "2.0", "error": {"code": -32602, "message": "two_positionals() got an unexpected keyword argument \'foo\'"}, "id": 1},
            {"jsonrpc": "2.0", "method": "two_positionals", "params": [1, {"foo": "bar"}], "id": 1}
        )

    # Test return results

    def test_add_two_numbers(self):
        self.post(
            {'jsonrpc': '2.0', 'result': 3, 'id': 1},
            {"jsonrpc": "2.0", "method": "add", "params": [1, 2], "id": 1}
        )

    def test_uppercase(self):
        self.post(
            {'jsonrpc': '2.0', 'result': 'TEST', 'id': 1},
            {"jsonrpc": "2.0", "method": "uppercase", "params": ["test"], "id": 1}
        )

    def test_lookup_surname(self):
        self.post(
            {'jsonrpc': '2.0', 'result': 'Smith', 'id': 1},
            {"jsonrpc": "2.0", "method": "lookup_surname", "params": {"firstname": "John"}, "id": 1}
        )
<|endoftext|>


<commit_before>import calendar
import croniter

from datetime import datetime

# from_unix from times.from_unix()
def from_unix(string):
    """Convert a unix timestamp into a utc datetime"""
    return datetime.utcfromtimestamp(float(string))

# to_unix from times.to_unix()
def to_unix(dt):
    """Converts a datetime object to unixtime"""
    return calendar.timegm(dt.utctimetuple())

def crontab_get_next_scheduled_time(crontab_string, crontab_start):
    """Calculate the next scheduled time by creating a crontab object
    with a crontab string and a start time to get the next time"""
    job = croniter.croniter(crontab_string, crontab_startc)
    return job.get_next(datetime)
<commit_msg>delete another typo<commit_after>import calendar
import croniter

from datetime import datetime

# from_unix from times.from_unix()
def from_unix(string):
    """Convert a unix timestamp into a utc datetime"""
    return datetime.utcfromtimestamp(float(string))

# to_unix from times.to_unix()
def to_unix(dt):
    """Converts a datetime object to unixtime"""
    return calendar.timegm(dt.utctimetuple())

def crontab_get_next_scheduled_time(crontab_string, crontab_start):
    """Calculate the next scheduled time by creating a crontab object
    with a crontab string and a start time to get the next time"""
    job = croniter.croniter(crontab_string, crontab_start)
    return job.get_next(datetime)
<|endoftext|>


<commit_before>import os
from abc import ABC, abstractmethod

import numpy as np
import torch
from torch.utils.data import Dataset, DataLoader
from torchvision.transforms import ToPILImage, RandomCrop, RandomHorizontalFlip, ToTensor, Normalize, Compose

from autokeras.constant import Constant
from autokeras.utils import read_csv_file, read_image

class OneHotEncoder:
    """A class that can format data.

    This class provides ways to transform data's classification label into vector.

    Attributes:
          data: The input data
          n_classes: The number of classes in the classification problem.
          labels: The number of labels.
          label_to_vec: Mapping from label to vector.
          int_to_label: Mapping from int to label.
    """

    def __init__(self):
        """Initialize a OneHotEncoder"""
        self.data = None
        self.n_classes = 0
        self.labels = None
        self.label_to_vec = {}
        self.int_to_label = {}

    def fit(self, data):
        """Create mapping from label to vector, and vector to label."""
        data = np.array(data).flatten()
        self.labels = set(data)
        self.n_classes = len(self.labels)
        for index, label in enumerate(self.labels):
            vec = np.array([0] * self.n_classes)
            vec[index] = 1
            self.label_to_vec[label] = vec
            self.int_to_label[index] = label

    def transform(self, data):
        """Get vector for every element in the data array."""
        data = np.array(data)
        if len(data.shape) > 1:
            data = data.flatten()
        return np.array(list(map(lambda x: self.label_to_vec[x], data)))

    def inverse_transform(self, data):
        """Get label for every element in data."""
        return np.array(list(map(lambda x: self.int_to_label[x], np.argmax(np.array(data), axis=1))))

class Cutout(object):
    """Randomly mask out one or more patches from an image.

    Args:
        n_holes (int): Number of patches to cut out of each image.
        length (int): The length (in pixels) of each square patch.
    """

    def __init__(self, n_holes, length):
        self.n_holes = n_holes
        self.length = length

    def __call__(self, img):
        """Perform the actual transformation.

        Args:
            img (Tensor): Tensor image of size (C, H, W).

        Returns:
            Tensor: Image with n_holes of dimension length x length cut out of it.
        """
        h = img.size(1)
        w = img.size(2)

        mask = np.ones((h, w), np.float32)

        for n in range(self.n_holes):
            y = np.random.randint(h)
            x = np.random.randint(w)

            y1 = np.clip(y - self.length // 2, 0, h)
            y2 = np.clip(y + self.length // 2, 0, h)
            x1 = np.clip(x - self.length // 2, 0, w)
            x2 = np.clip(x + self.length // 2, 0, w)

            mask[y1: y2, x1: x2] = 0.

        mask = torch.from_numpy(mask)
        mask = mask.expand_as(img)
        img = img * mask

        return img

class DataTransformer(ABC):
    """A superclass for all the DataTransformer."""

    def __init__(self):
        pass

    @abstractmethod
    def transform_train(self, data, targets=None, batch_size=None):
        """ Transform the training data and get the DataLoader class.

        Args:
            data: x.
            targets: y.
            batch_size: the batch size.

        Returns:
            dataloader: A torch.DataLoader class to represent the transformed data.
        """
        raise NotImplementedError

    @abstractmethod
    def transform_test(self, data, targets=None, batch_size=None):
        """ Transform the training data and get the DataLoader class.

        Args:
            data: x.
            targets: y.
            batch_size: the batch size.

        Returns:
            dataloader: A torch.DataLoader class to represent the transformed data.
        """
        raise NotImplementedError

def text_transform(compose_list, data, targets):
    data = torch.Tensor(data.transpose(0, 2, 1))
    data_transforms = Compose(compose_list)
    return MultiTransformDataset(data, targets, data_transforms)

class TextDataTransformer(DataTransformer):
    """ A DataTransformer class for the text data."""

    def __init__(self):
        super().__init__()

    def transform_train(self, data, targets=None, batch_size=None):
        """Transform the training dataset."""
        dataset = text_transform(compose_list=[], data=data, targets=targets)
        if batch_size is None:
            batch_size = Constant.MAX_BATCH_SIZE
        batch_size = min(len(data), batch_size)

        return DataLoader(dataset, batch_size=batch_size, shuffle=True)

    def transform_test(self, data, targets=None, batch_size=None):
        """Transform the testing dataset."""
        dataset = text_transform(compose_list=[], data=data, targets=targets)
        if batch_size is None:
            batch_size = Constant.MAX_BATCH_SIZE
        batch_size = min(len(data), batch_size)

        return DataLoader(dataset, batch_size=batch_size, shuffle=True)

class ImageDataTransformer(DataTransformer):
    """ Perform basic image transformation and augmentation.

    Attributes:
        max_val: the maximum value of all data.
        mean: the mean value.
        std: the standard deviation.
        augment: whether to perform augmentation on data.
    """

    def __init__(self, data, augment=None):
        super().__init__()
        self.max_val = data.max()
        data = data / self.max_val
        self.mean = np.mean(data, axis=(0, 1, 2), keepdims=True).flatten()
        self.std = np.std(data, axis=(0, 1, 2), keepdims=True).flatten()
        if augment is None:
            self.augment = Constant.DATA_AUGMENTATION
        self.augment = augment

    def transform_train(self, data, targets=None, batch_size=None):
        """ Transform the training data, perform random cropping data augmentation and basic random flip augmentation.

        Args:
            data: Numpy array. The data to be transformed.
            batch_size: int batch_size.
            targets: the target of training set.

        Returns:
            A DataLoader class instance.
        """
        short_edge_length = min(data.shape[1], data.shape[2])
        common_list = [Normalize(torch.Tensor(self.mean), torch.Tensor(self.std))]
        if self.augment:
            compose_list = [ToPILImage(),
                            RandomCrop(data.shape[1:3], padding=4),
                            RandomHorizontalFlip(),
                            ToTensor()
                            ] + common_list + [Cutout(n_holes=Constant.CUTOUT_HOLES,
                                                      length=int(short_edge_length * Constant.CUTOUT_RATIO))]
        else:
            compose_list = common_list

        if len(data.shape) != 4:
            compose_list = []

        dataset = self._transform(compose_list, data, targets)

        if batch_size is None:
            batch_size = Constant.MAX_BATCH_SIZE
        batch_size = min(len(data), batch_size)

        return DataLoader(dataset, batch_size=batch_size, shuffle=True)

    def transform_test(self, data, targets=None, batch_size=None):
        """ Transform the test data, perform normalization.

        Args:
            data: Numpy array. The data to be transformed.
            batch_size: int batch_size.
            targets: the target of test set.
        Returns:
            A DataLoader instance.
        """
        common_list = [Normalize(torch.Tensor(self.mean), torch.Tensor(self.std))]
        compose_list = common_list
        if len(data.shape) != 4:
            compose_list = []

        dataset = self._transform(compose_list, data, targets)

        if batch_size is None:
            batch_size = Constant.MAX_BATCH_SIZE
        batch_size = min(len(data), batch_size)

        return DataLoader(dataset, batch_size=batch_size, shuffle=False)

    def _transform(self, compose_list, data, targets):
        """Perform the actual transformation.

        Args:
            compose_list: a list of transforming operation.
            data: x.
            targets: y.

        Returns:
            A MultiTransformDataset class to represent the dataset.
        """
        data = data / self.max_val
        args = [0, len(data.shape) - 1] + list(range(1, len(data.shape) - 1))
        data = torch.Tensor(data.transpose(*args))
        data_transforms = Compose(compose_list)
        return MultiTransformDataset(data, targets, data_transforms)

class DataTransformerMlp(DataTransformer):
    def __init__(self, data):
        super().__init__()
        self.max_val = data.max()
        data = data / self.max_val
        self.mean = np.mean(data, axis=0, keepdims=True).flatten()
        self.std = np.std(data, axis=0, keepdims=True).flatten()

    def transform_train(self, data, targets=None, batch_size=None):
        dataset = self._transform([Normalize(torch.Tensor(self.mean), torch.Tensor(self.std))], data, targets)

        if batch_size is None:
            batch_size = Constant.MAX_BATCH_SIZE
        batch_size = min(len(data), batch_size)

        return DataLoader(dataset, batch_size=batch_size, shuffle=True)

    def transform_test(self, data, target=None, batch_size=None):
        return self.transform_train(data, targets=target, batch_size=batch_size)

    def _transform(self, compose_list, data, targets):
        data = data / self.max_val
        args = [0, len(data.shape) - 1] + list(range(1, len(data.shape) - 1))
        data = torch.Tensor(data.transpose(*args))
        data_transforms = Compose(compose_list)
        return MultiTransformDataset(data, targets, data_transforms)

class MultiTransformDataset(Dataset):
    """A class incorporate all transform method into a torch.Dataset class."""

    def __init__(self, dataset, target, compose):
        self.dataset = dataset
        self.target = target
        self.compose = compose

    def __getitem__(self, index):
        feature = self.dataset[index]
        if self.target is None:
            return self.compose(feature)
        return self.compose(feature), self.target[index]

    def __len__(self):
        return len(self.dataset)

class BatchDataset(Dataset):
    """A torch.Dataset class that can read data batch by batch."""

    def __init__(self, csv_file_path, image_path, has_target=True):
        file_names, target = read_csv_file(csv_file_path)

        self.y_encoder = OneHotEncoder()
        self.y_encoder.fit(target)
        target = self.y_encoder.transform(target)

        self.target = target
        self.has_target = has_target
        self.file_paths = list(map(lambda file_name: os.path.join(image_path, file_name), file_names))

    def __getitem__(self, index):
        image = read_image(self.file_paths[index])
        if len(image.shape) < 3:
            image = image[..., np.newaxis]
        image = torch.Tensor(image.transpose(2, 0, 1))
        if self.has_target:
            return image, self.target[index]
        return image

    def __len__(self):
        return len(self.file_paths)
<commit_msg>fix the assignment of augment (#445)<commit_after>import os
from abc import ABC, abstractmethod

import numpy as np
import torch
from torch.utils.data import Dataset, DataLoader
from torchvision.transforms import ToPILImage, RandomCrop, RandomHorizontalFlip, ToTensor, Normalize, Compose

from autokeras.constant import Constant
from autokeras.utils import read_csv_file, read_image

class OneHotEncoder:
    """A class that can format data.

    This class provides ways to transform data's classification label into vector.

    Attributes:
          data: The input data
          n_classes: The number of classes in the classification problem.
          labels: The number of labels.
          label_to_vec: Mapping from label to vector.
          int_to_label: Mapping from int to label.
    """

    def __init__(self):
        """Initialize a OneHotEncoder"""
        self.data = None
        self.n_classes = 0
        self.labels = None
        self.label_to_vec = {}
        self.int_to_label = {}

    def fit(self, data):
        """Create mapping from label to vector, and vector to label."""
        data = np.array(data).flatten()
        self.labels = set(data)
        self.n_classes = len(self.labels)
        for index, label in enumerate(self.labels):
            vec = np.array([0] * self.n_classes)
            vec[index] = 1
            self.label_to_vec[label] = vec
            self.int_to_label[index] = label

    def transform(self, data):
        """Get vector for every element in the data array."""
        data = np.array(data)
        if len(data.shape) > 1:
            data = data.flatten()
        return np.array(list(map(lambda x: self.label_to_vec[x], data)))

    def inverse_transform(self, data):
        """Get label for every element in data."""
        return np.array(list(map(lambda x: self.int_to_label[x], np.argmax(np.array(data), axis=1))))

class Cutout(object):
    """Randomly mask out one or more patches from an image.

    Args:
        n_holes (int): Number of patches to cut out of each image.
        length (int): The length (in pixels) of each square patch.
    """

    def __init__(self, n_holes, length):
        self.n_holes = n_holes
        self.length = length

    def __call__(self, img):
        """Perform the actual transformation.

        Args:
            img (Tensor): Tensor image of size (C, H, W).

        Returns:
            Tensor: Image with n_holes of dimension length x length cut out of it.
        """
        h = img.size(1)
        w = img.size(2)

        mask = np.ones((h, w), np.float32)

        for n in range(self.n_holes):
            y = np.random.randint(h)
            x = np.random.randint(w)

            y1 = np.clip(y - self.length // 2, 0, h)
            y2 = np.clip(y + self.length // 2, 0, h)
            x1 = np.clip(x - self.length // 2, 0, w)
            x2 = np.clip(x + self.length // 2, 0, w)

            mask[y1: y2, x1: x2] = 0.

        mask = torch.from_numpy(mask)
        mask = mask.expand_as(img)
        img = img * mask

        return img

class DataTransformer(ABC):
    """A superclass for all the DataTransformer."""

    def __init__(self):
        pass

    @abstractmethod
    def transform_train(self, data, targets=None, batch_size=None):
        """ Transform the training data and get the DataLoader class.

        Args:
            data: x.
            targets: y.
            batch_size: the batch size.

        Returns:
            dataloader: A torch.DataLoader class to represent the transformed data.
        """
        raise NotImplementedError

    @abstractmethod
    def transform_test(self, data, targets=None, batch_size=None):
        """ Transform the training data and get the DataLoader class.

        Args:
            data: x.
            targets: y.
            batch_size: the batch size.

        Returns:
            dataloader: A torch.DataLoader class to represent the transformed data.
        """
        raise NotImplementedError

def text_transform(compose_list, data, targets):
    data = torch.Tensor(data.transpose(0, 2, 1))
    data_transforms = Compose(compose_list)
    return MultiTransformDataset(data, targets, data_transforms)

class TextDataTransformer(DataTransformer):
    """ A DataTransformer class for the text data."""

    def __init__(self):
        super().__init__()

    def transform_train(self, data, targets=None, batch_size=None):
        """Transform the training dataset."""
        dataset = text_transform(compose_list=[], data=data, targets=targets)
        if batch_size is None:
            batch_size = Constant.MAX_BATCH_SIZE
        batch_size = min(len(data), batch_size)

        return DataLoader(dataset, batch_size=batch_size, shuffle=True)

    def transform_test(self, data, targets=None, batch_size=None):
        """Transform the testing dataset."""
        dataset = text_transform(compose_list=[], data=data, targets=targets)
        if batch_size is None:
            batch_size = Constant.MAX_BATCH_SIZE
        batch_size = min(len(data), batch_size)

        return DataLoader(dataset, batch_size=batch_size, shuffle=True)

class ImageDataTransformer(DataTransformer):
    """ Perform basic image transformation and augmentation.

    Attributes:
        max_val: the maximum value of all data.
        mean: the mean value.
        std: the standard deviation.
        augment: whether to perform augmentation on data.
    """

    def __init__(self, data, augment=None):
        super().__init__()
        self.max_val = data.max()
        data = data / self.max_val
        self.mean = np.mean(data, axis=(0, 1, 2), keepdims=True).flatten()
        self.std = np.std(data, axis=(0, 1, 2), keepdims=True).flatten()
        if augment is None:
            self.augment = Constant.DATA_AUGMENTATION
        else:
            self.augment = augment

    def transform_train(self, data, targets=None, batch_size=None):
        """ Transform the training data, perform random cropping data augmentation and basic random flip augmentation.

        Args:
            data: Numpy array. The data to be transformed.
            batch_size: int batch_size.
            targets: the target of training set.

        Returns:
            A DataLoader class instance.
        """
        short_edge_length = min(data.shape[1], data.shape[2])
        common_list = [Normalize(torch.Tensor(self.mean), torch.Tensor(self.std))]
        if self.augment:
            compose_list = [ToPILImage(),
                            RandomCrop(data.shape[1:3], padding=4),
                            RandomHorizontalFlip(),
                            ToTensor()
                            ] + common_list + [Cutout(n_holes=Constant.CUTOUT_HOLES,
                                                      length=int(short_edge_length * Constant.CUTOUT_RATIO))]
        else:
            compose_list = common_list

        if len(data.shape) != 4:
            compose_list = []

        dataset = self._transform(compose_list, data, targets)

        if batch_size is None:
            batch_size = Constant.MAX_BATCH_SIZE
        batch_size = min(len(data), batch_size)

        return DataLoader(dataset, batch_size=batch_size, shuffle=True)

    def transform_test(self, data, targets=None, batch_size=None):
        """ Transform the test data, perform normalization.

        Args:
            data: Numpy array. The data to be transformed.
            batch_size: int batch_size.
            targets: the target of test set.
        Returns:
            A DataLoader instance.
        """
        common_list = [Normalize(torch.Tensor(self.mean), torch.Tensor(self.std))]
        compose_list = common_list
        if len(data.shape) != 4:
            compose_list = []

        dataset = self._transform(compose_list, data, targets)

        if batch_size is None:
            batch_size = Constant.MAX_BATCH_SIZE
        batch_size = min(len(data), batch_size)

        return DataLoader(dataset, batch_size=batch_size, shuffle=False)

    def _transform(self, compose_list, data, targets):
        """Perform the actual transformation.

        Args:
            compose_list: a list of transforming operation.
            data: x.
            targets: y.

        Returns:
            A MultiTransformDataset class to represent the dataset.
        """
        data = data / self.max_val
        args = [0, len(data.shape) - 1] + list(range(1, len(data.shape) - 1))
        data = torch.Tensor(data.transpose(*args))
        data_transforms = Compose(compose_list)
        return MultiTransformDataset(data, targets, data_transforms)

class DataTransformerMlp(DataTransformer):
    def __init__(self, data):
        super().__init__()
        self.max_val = data.max()
        data = data / self.max_val
        self.mean = np.mean(data, axis=0, keepdims=True).flatten()
        self.std = np.std(data, axis=0, keepdims=True).flatten()

    def transform_train(self, data, targets=None, batch_size=None):
        dataset = self._transform([Normalize(torch.Tensor(self.mean), torch.Tensor(self.std))], data, targets)

        if batch_size is None:
            batch_size = Constant.MAX_BATCH_SIZE
        batch_size = min(len(data), batch_size)

        return DataLoader(dataset, batch_size=batch_size, shuffle=True)

    def transform_test(self, data, target=None, batch_size=None):
        return self.transform_train(data, targets=target, batch_size=batch_size)

    def _transform(self, compose_list, data, targets):
        data = data / self.max_val
        args = [0, len(data.shape) - 1] + list(range(1, len(data.shape) - 1))
        data = torch.Tensor(data.transpose(*args))
        data_transforms = Compose(compose_list)
        return MultiTransformDataset(data, targets, data_transforms)

class MultiTransformDataset(Dataset):
    """A class incorporate all transform method into a torch.Dataset class."""

    def __init__(self, dataset, target, compose):
        self.dataset = dataset
        self.target = target
        self.compose = compose

    def __getitem__(self, index):
        feature = self.dataset[index]
        if self.target is None:
            return self.compose(feature)
        return self.compose(feature), self.target[index]

    def __len__(self):
        return len(self.dataset)

class BatchDataset(Dataset):
    """A torch.Dataset class that can read data batch by batch."""

    def __init__(self, csv_file_path, image_path, has_target=True):
        file_names, target = read_csv_file(csv_file_path)

        self.y_encoder = OneHotEncoder()
        self.y_encoder.fit(target)
        target = self.y_encoder.transform(target)

        self.target = target
        self.has_target = has_target
        self.file_paths = list(map(lambda file_name: os.path.join(image_path, file_name), file_names))

    def __getitem__(self, index):
        image = read_image(self.file_paths[index])
        if len(image.shape) < 3:
            image = image[..., np.newaxis]
        image = torch.Tensor(image.transpose(2, 0, 1))
        if self.has_target:
            return image, self.target[index]
        return image

    def __len__(self):
        return len(self.file_paths)
<|endoftext|>


<commit_before>import re

from flask import Blueprint, g, request, redirect
from dateutil.parser import parse as dateparse
from twilio import twiml

from calloncongress import data, logger
from calloncongress.utils import twilioify

voice = Blueprint('voice', __name__)

def bill_type(abbr):
    abbr = re.split(r'([a-zA-Z.\-]*)', abbr)[1].lower().replace('.', '')
    return {
        'hr': 'House Bill',
        'hres': 'House Resolution',
        'hjres': 'House Joint Resolution',
        'hcres': 'House Concurrent Resolution',
        's': 'Senate Bill',
        'sres': 'Senate Resolution',
        'sjres': 'Senate Joint Resolution',
        'scres': 'Senate Concurrent Resolution',
    }.get(abbr)

def handle_selection(selection):
    r = twiml.Response()

    if selection == '1':

        contribs = data.top_contributors(g.legislator)
        script = " ".join("%(name)s contributed $%(total_amount)s.\n" % c for c in contribs)

        r.play('http://assets.sunlightfoundation.com/projects/transparencyconnect/audio/1.wav')
        r.say(script)

        with r.gather(numDigits=1, timeout=10, action='/next/2') as rg:
            rg.play('http://assets.sunlightfoundation.com/projects/transparencyconnect/audio/1-out.wav')

    elif selection == '2':

        votes = data.recent_votes(g.legislator)

        script = " ".join("On %(question)s. Voted %(voted)s. . The bill %(result)s.\t" % v for v in votes)

        r.play('http://assets.sunlightfoundation.com/projects/transparencyconnect/audio/2.wav')
        r.say("%s. %s" % (g.legislator['fullname'], script))

        with r.gather(numDigits=1, timeout=10, action='/next/3') as rg:
            rg.play('http://assets.sunlightfoundation.com/projects/transparencyconnect/audio/2-out.wav')

    elif selection == '3':

        bio = data.legislator_bio(g.legislator)

        r.say(bio or ('Sorry, we were unable to locate a biography for %s' % g.legislator['fullname']))

        with r.gather(numDigits=1, timeout=10, action='/next/4') as rg:
            rg.play('http://assets.sunlightfoundation.com/projects/transparencyconnect/audio/3-out.wav')

    elif selection == '4':

        comms = data.committees(g.legislator)

        r.say(g.legislator['fullname'])
        r.play('http://assets.sunlightfoundation.com/projects/transparencyconnect/audio/4.wav')
        r.say(comms)

        with r.gather(numDigits=1, timeout=10, action='/next/5') as rg:
            rg.play('http://assets.sunlightfoundation.com/projects/transparencyconnect/audio/4-out.wav')

    elif selection == '5':

        # connect to the member's office

        r.play('http://assets.sunlightfoundation.com/projects/transparencyconnect/audio/5-pre.wav')
        r.say(g.legislator['fullname'])
        r.play('http://assets.sunlightfoundation.com/projects/transparencyconnect/audio/5-post.wav')

        with r.dial() as rd:
            rd.number(g.legislator['phone'])

    elif selection == '9':

        with r.gather(numDigits=1, timeout=10, action='/signup') as rg:
            rg.play('http://assets.sunlightfoundation.com/projects/transparencyconnect/audio/9.wav')

    elif selection == '0':
        r.redirect('/zipcode')

    else:
        r.say("I'm sorry, I don't recognize that selection. I will read you the options again.")
        r.redirect('/reps')

    return r

@voice.route("", methods=['GET', 'POST'])
@twilioify
def call_init():

    r = twiml.Response()

    if request.method == 'POST':

        options = {
            '1': 'en',
            '2': 'es',
        }

        sel = request.form.get('Digits')
        g.call['language'] = options.get(sel, 'en')

        r.redirect('/voice/welcome')

    else:
        with r.gather(numDigits=1, timeout=10, action='/voice', method='POST') as rg:
            rg.say('Welcome to Call on Congress. Press 1 to continue in English.', language='en')
            rg.say('Presione 2 para continuar en espanol.', language='es')

    return str(r)

@voice.route("/welcome", methods=['GET', 'POST'])
@twilioify
def welcome():
    """ Initiate a new call. Welcomes the user and prompts for zipcode.
    """

    r = twiml.Response()
    #r.say("Welcome to CapitolPhone brought to you by the Sunlight Foundation.")
    #with r.gather(numDigits=5, timeout=10, action='/zipcode') as rg:
        #rg.say("In order to locate your representatives, please enter your five digit zipcode now.")

    r.play("http://assets.sunlightfoundation.com/projects/transparencyconnect/audio/intro.wav")
    r.gather(numDigits=5, timeout=10, action='/zipcode')

    return r

@voice.route("/zipcode", methods=['POST'])
@twilioify
def zipcode():
    """ Handles POSTed zipcode and prompts for legislator selection.
    """

    zipcode = request.form.get('Digits', g.zipcode)
    r = twiml.Response()

    if zipcode == '00000':

        r.say("""
            Welcome to movie phone.
            You seem like the type of person that would enjoy The Twilight Saga: Breaking Dawn Part 1.
            The best showings are during the day, but you'll be stuck in middle school.
            Ha ha ha. Loser.
        """)

    else:

        g.call['context']['zipcode'] = zipcode

        legislators = data.legislators_for_zip(zipcode)

        if legislators:

            options = [(l['fullname'], l['bioguide_id']) for l in legislators]
            script = " ".join("Press %i for %s." % (index + 1, o[0]) for index, o in enumerate(options))
            script += " Press 0 to enter a new zipcode."

            if len(legislators) > 3:
                r.play('http://assets.sunlightfoundation.com/projects/transparencyconnect/audio/selectlegalt.wav')
            else:
                r.play('http://assets.sunlightfoundation.com/projects/transparencyconnect/audio/selectleg.wav')

            with r.gather(numDigits=1, timeout=10, action='/reps') as rg:
                rg.say(script)

        else:

            r.say("I'm sorry, I wasn't able to locate any representatives for %s." % (" ".join(zipcode),))
            with r.gather(numDigits=5, timeout=10, action='/zipcode') as rg:
                rg.say("Please try again or enter a new zipcode.")

    return r

@voice.route("/reps", methods=['POST'])
@twilioify
def reps():
    r = twiml.Response()

    if 'Digits' in request.form:

        digits = request.form.get('Digits', None)

        if digits == '0':

            r.redirect('')
            return r  # shortcut the process and start over

        else:

            selection = int(digits) - 1
            legislator = data.legislators_for_zip(g.zipcode)[selection]
            g.call['context']['legislator'] = legislator

    else:
        legislator = g.legislator

    r.play('http://assets.sunlightfoundation.com/projects/transparencyconnect/audio/mainmenu-intro.wav')
    r.say('%s' % legislator['fullname'])
    with r.gather(numDigits=1, timeout=30, action='/rep') as rg:
        rg.play('http://assets.sunlightfoundation.com/projects/transparencyconnect/audio/mainmenu.wav')

    return r

@voice.route("/rep", methods=['POST'])
@twilioify
def rep():
    selection = request.form.get('Digits', None)
    return handle_selection(selection)

@voice.route("/next/<next_selection>", methods=['POST'])
@twilioify
def next(next_selection):
    selection = request.form.get('Digits', None)
    if selection == '1':
        return handle_selection(next_selection)
    else:
        r = twiml.Response()
        r.redirect('/reps')
        return r

@voice.route("/signup", methods=['POST'])
@twilioify
def signup():

    r = twiml.Response()

    selection = request.form.get('Digits', None)

    if selection == '1':

        g.db.smsSignups.insert({
            'url': g.call['from'],
            'timestamp': g.now,
        })

        r.play('http://assets.sunlightfoundation.com/projects/transparencyconnect/audio/9-1.wav')

        r.redirect('/reps')

    elif selection == '2':

        r.play('http://assets.sunlightfoundation.com/projects/transparencyconnect/audio/9-2.wav')
        r.record(action='/message', timeout=10, maxLength=120)
        r.redirect('/reps')

    elif selection == '3':

        r.play('http://assets.sunlightfoundation.com/projects/transparencyconnect/audio/9-3.wav')
        r.redirect('/reps')

    else:
        r.redirect('/reps')

    return r

@voice.route("/message", methods=['POST'])
@twilioify
def message():
    g.db.messages.insert({
        'url': request.form['RecordingUrl'],
        'timestamp': g.now,
    })
    r = twiml.Response()
    r.redirect('/reps')
    return r

@voice.route("/upcoming-bills", methods=['GET', 'POST'])
# @twilioify
def upcoming_bills():
    r = twiml.Response()
    bills = data.upcoming_bills()[:9]
    if not len(bills):
        r.say('There are no bills in the news this week.')
    else:
        r.say('The following bills are coming up in the next few days:')
        for bill in bills:
            bill_context = {
                'date': dateparse(bill.legislative_day).strftime('%B %e'),
                'chamber': bill.chamber,
                'bill_type': bill_type(bill.bill_id),
                'bill_number': bill.bill['number'],
                'bill_title': bill.bill['official_title'].encode('ascii', 'ignore'),
                'bill_description': '\n'.join(bill.context).encode('ascii', 'ignore')
            }
            r.say('''On {date}, the {chamber} will discuss {bill_type} {bill_number},
                     {bill_title}. {bill_description}
                  '''.format(**bill_context))

    return r

@voice.route("/test", methods=['GET'])
def test_method():
    r = data.recent_votes({'bioguide_id': 'V000128'})
    return str(r)
<commit_msg>bill.context can be empty<commit_after>import re

from flask import Blueprint, g, request, redirect
from dateutil.parser import parse as dateparse
from twilio import twiml

from calloncongress import data, logger
from calloncongress.utils import twilioify

voice = Blueprint('voice', __name__)

def bill_type(abbr):
    abbr = re.split(r'([a-zA-Z.\-]*)', abbr)[1].lower().replace('.', '')
    return {
        'hr': 'House Bill',
        'hres': 'House Resolution',
        'hjres': 'House Joint Resolution',
        'hcres': 'House Concurrent Resolution',
        's': 'Senate Bill',
        'sres': 'Senate Resolution',
        'sjres': 'Senate Joint Resolution',
        'scres': 'Senate Concurrent Resolution',
    }.get(abbr)

def handle_selection(selection):
    r = twiml.Response()

    if selection == '1':

        contribs = data.top_contributors(g.legislator)
        script = " ".join("%(name)s contributed $%(total_amount)s.\n" % c for c in contribs)

        r.play('http://assets.sunlightfoundation.com/projects/transparencyconnect/audio/1.wav')
        r.say(script)

        with r.gather(numDigits=1, timeout=10, action='/next/2') as rg:
            rg.play('http://assets.sunlightfoundation.com/projects/transparencyconnect/audio/1-out.wav')

    elif selection == '2':

        votes = data.recent_votes(g.legislator)

        script = " ".join("On %(question)s. Voted %(voted)s. . The bill %(result)s.\t" % v for v in votes)

        r.play('http://assets.sunlightfoundation.com/projects/transparencyconnect/audio/2.wav')
        r.say("%s. %s" % (g.legislator['fullname'], script))

        with r.gather(numDigits=1, timeout=10, action='/next/3') as rg:
            rg.play('http://assets.sunlightfoundation.com/projects/transparencyconnect/audio/2-out.wav')

    elif selection == '3':

        bio = data.legislator_bio(g.legislator)

        r.say(bio or ('Sorry, we were unable to locate a biography for %s' % g.legislator['fullname']))

        with r.gather(numDigits=1, timeout=10, action='/next/4') as rg:
            rg.play('http://assets.sunlightfoundation.com/projects/transparencyconnect/audio/3-out.wav')

    elif selection == '4':

        comms = data.committees(g.legislator)

        r.say(g.legislator['fullname'])
        r.play('http://assets.sunlightfoundation.com/projects/transparencyconnect/audio/4.wav')
        r.say(comms)

        with r.gather(numDigits=1, timeout=10, action='/next/5') as rg:
            rg.play('http://assets.sunlightfoundation.com/projects/transparencyconnect/audio/4-out.wav')

    elif selection == '5':

        # connect to the member's office

        r.play('http://assets.sunlightfoundation.com/projects/transparencyconnect/audio/5-pre.wav')
        r.say(g.legislator['fullname'])
        r.play('http://assets.sunlightfoundation.com/projects/transparencyconnect/audio/5-post.wav')

        with r.dial() as rd:
            rd.number(g.legislator['phone'])

    elif selection == '9':

        with r.gather(numDigits=1, timeout=10, action='/signup') as rg:
            rg.play('http://assets.sunlightfoundation.com/projects/transparencyconnect/audio/9.wav')

    elif selection == '0':
        r.redirect('/zipcode')

    else:
        r.say("I'm sorry, I don't recognize that selection. I will read you the options again.")
        r.redirect('/reps')

    return r

@voice.route("", methods=['GET', 'POST'])
@twilioify
def call_init():

    r = twiml.Response()

    if request.method == 'POST':

        options = {
            '1': 'en',
            '2': 'es',
        }

        sel = request.form.get('Digits')
        g.call['language'] = options.get(sel, 'en')

        r.redirect('/voice/welcome')

    else:
        with r.gather(numDigits=1, timeout=10, action='/voice', method='POST') as rg:
            rg.say('Welcome to Call on Congress. Press 1 to continue in English.', language='en')
            rg.say('Presione 2 para continuar en espanol.', language='es')

    return str(r)

@voice.route("/welcome", methods=['GET', 'POST'])
@twilioify
def welcome():
    """ Initiate a new call. Welcomes the user and prompts for zipcode.
    """

    r = twiml.Response()
    #r.say("Welcome to CapitolPhone brought to you by the Sunlight Foundation.")
    #with r.gather(numDigits=5, timeout=10, action='/zipcode') as rg:
        #rg.say("In order to locate your representatives, please enter your five digit zipcode now.")

    r.play("http://assets.sunlightfoundation.com/projects/transparencyconnect/audio/intro.wav")
    r.gather(numDigits=5, timeout=10, action='/zipcode')

    return r

@voice.route("/zipcode", methods=['POST'])
@twilioify
def zipcode():
    """ Handles POSTed zipcode and prompts for legislator selection.
    """

    zipcode = request.form.get('Digits', g.zipcode)
    r = twiml.Response()

    if zipcode == '00000':

        r.say("""
            Welcome to movie phone.
            You seem like the type of person that would enjoy The Twilight Saga: Breaking Dawn Part 1.
            The best showings are during the day, but you'll be stuck in middle school.
            Ha ha ha. Loser.
        """)

    else:

        g.call['context']['zipcode'] = zipcode

        legislators = data.legislators_for_zip(zipcode)

        if legislators:

            options = [(l['fullname'], l['bioguide_id']) for l in legislators]
            script = " ".join("Press %i for %s." % (index + 1, o[0]) for index, o in enumerate(options))
            script += " Press 0 to enter a new zipcode."

            if len(legislators) > 3:
                r.play('http://assets.sunlightfoundation.com/projects/transparencyconnect/audio/selectlegalt.wav')
            else:
                r.play('http://assets.sunlightfoundation.com/projects/transparencyconnect/audio/selectleg.wav')

            with r.gather(numDigits=1, timeout=10, action='/reps') as rg:
                rg.say(script)

        else:

            r.say("I'm sorry, I wasn't able to locate any representatives for %s." % (" ".join(zipcode),))
            with r.gather(numDigits=5, timeout=10, action='/zipcode') as rg:
                rg.say("Please try again or enter a new zipcode.")

    return r

@voice.route("/reps", methods=['POST'])
@twilioify
def reps():
    r = twiml.Response()

    if 'Digits' in request.form:

        digits = request.form.get('Digits', None)

        if digits == '0':

            r.redirect('')
            return r  # shortcut the process and start over

        else:

            selection = int(digits) - 1
            legislator = data.legislators_for_zip(g.zipcode)[selection]
            g.call['context']['legislator'] = legislator

    else:
        legislator = g.legislator

    r.play('http://assets.sunlightfoundation.com/projects/transparencyconnect/audio/mainmenu-intro.wav')
    r.say('%s' % legislator['fullname'])
    with r.gather(numDigits=1, timeout=30, action='/rep') as rg:
        rg.play('http://assets.sunlightfoundation.com/projects/transparencyconnect/audio/mainmenu.wav')

    return r

@voice.route("/rep", methods=['POST'])
@twilioify
def rep():
    selection = request.form.get('Digits', None)
    return handle_selection(selection)

@voice.route("/next/<next_selection>", methods=['POST'])
@twilioify
def next(next_selection):
    selection = request.form.get('Digits', None)
    if selection == '1':
        return handle_selection(next_selection)
    else:
        r = twiml.Response()
        r.redirect('/reps')
        return r

@voice.route("/signup", methods=['POST'])
@twilioify
def signup():

    r = twiml.Response()

    selection = request.form.get('Digits', None)

    if selection == '1':

        g.db.smsSignups.insert({
            'url': g.call['from'],
            'timestamp': g.now,
        })

        r.play('http://assets.sunlightfoundation.com/projects/transparencyconnect/audio/9-1.wav')

        r.redirect('/reps')

    elif selection == '2':

        r.play('http://assets.sunlightfoundation.com/projects/transparencyconnect/audio/9-2.wav')
        r.record(action='/message', timeout=10, maxLength=120)
        r.redirect('/reps')

    elif selection == '3':

        r.play('http://assets.sunlightfoundation.com/projects/transparencyconnect/audio/9-3.wav')
        r.redirect('/reps')

    else:
        r.redirect('/reps')

    return r

@voice.route("/message", methods=['POST'])
@twilioify
def message():
    g.db.messages.insert({
        'url': request.form['RecordingUrl'],
        'timestamp': g.now,
    })
    r = twiml.Response()
    r.redirect('/reps')
    return r

@voice.route("/upcoming-bills", methods=['GET', 'POST'])
# @twilioify
def upcoming_bills():
    r = twiml.Response()
    bills = data.upcoming_bills()[:9]
    if not len(bills):
        r.say('There are no bills in the news this week.')
    else:
        r.say('The following bills are coming up in the next few days:')
        for bill in bills:
            try:
                ctx = bill.context
            except AttributeError:
                ctx = []
            bill_context = {
                'date': dateparse(bill.legislative_day).strftime('%B %e'),
                'chamber': bill.chamber,
                'bill_type': bill_type(bill.bill_id),
                'bill_number': bill.bill['number'],
                'bill_title': bill.bill['official_title'].encode('ascii', 'ignore'),
                'bill_description': '\n'.join(ctx).encode('ascii', 'ignore')
            }
            r.say('''On {date}, the {chamber} will discuss {bill_type} {bill_number},
                     {bill_title}. {bill_description}
                  '''.format(**bill_context))

    return r

@voice.route("/test", methods=['GET'])
def test_method():
    r = data.recent_votes({'bioguide_id': 'V000128'})
    return str(r)
<|endoftext|>


<commit_before>from .models import Path

from caminae.common.filters import OptionalRangeFilter, StructureRelatedFilterSet

class PathFilter(StructureRelatedFilterSet):
    length = OptionalRangeFilter()

    class Meta(StructureRelatedFilterSet.Meta):
        model = Path
        fields = StructureRelatedFilterSet.Meta.fields + ['length',]
<commit_msg>Force field label for path length (ref #143)<commit_after>from django.utils.translation import ugettext_lazy as _

from .models import Path

from caminae.common.filters import OptionalRangeFilter, StructureRelatedFilterSet

class PathFilter(StructureRelatedFilterSet):
    length = OptionalRangeFilter(label=_('length'))   # TODO: why force ?

    class Meta(StructureRelatedFilterSet.Meta):
        model = Path
        fields = StructureRelatedFilterSet.Meta.fields + ['length',]
<|endoftext|>


<commit_before>from typing import List

from hwtHls.ssa.context import SsaContext
from hwtHls.ssa.instr import SsaInstrBranch, SsaInstr
from hwtHls.ssa.phi import SsaPhi

class SsaBasicBlock():
    """
    Basic Block from Static Single Assignment (SSA) normal form of code.

    :ivar label: label for debug purposes
    :ivar predecessors: list of block from where the control flow can go to this block
    :ivar phis: list of phi functions which are selecting a value for a variable based on predecessor block
    :ivar body: statements of this block
    :ivar successors: an object to keep track of jumps from this block
    :ivar origns: list of objects which contributed to existence of this object
    """

    def __init__(self, ctx: SsaContext, label:str):
        self.ctx = ctx
        self.label = label
        self.predecessors: List[SsaBasicBlock] = []
        self.phis: List[SsaPhi] = []
        self.body: List[SsaInstr] = []
        self.successors = SsaInstrBranch(self)
        self.origins = []

    def appendPhi(self, phi: SsaPhi):
        assert phi.block is None, (phi, phi.block, self)
        assert not self.body, ("Adding phi if already have instructions", self, phi)
        phi.block = self
        self.phis.append(phi)

    def insertPhi(self, index: int, phi: SsaPhi):
        assert phi.block is None, (phi, phi.block, self)
        phi.block = self
        self.phis.insert(index, phi)

    def appendInstruction(self, instr: SsaInstr):
        assert instr.block is None, (instr, instr.block, self)
        instr.block = self
        self.body.append(instr)

    def insertInstruction(self, index: int, instr: SsaInstr):
        assert instr.block is None, (instr, instr.block, self)
        instr.block = self
        self.body.insert(index, instr)

    def __repr__(self):
        return f"<{self.__class__.__name__:s} {self.label:s}>"
<commit_msg>SsaBasicBlock.appendPhi rm assert<commit_after>from typing import List

from hwtHls.ssa.context import SsaContext
from hwtHls.ssa.instr import SsaInstrBranch, SsaInstr
from hwtHls.ssa.phi import SsaPhi

class SsaBasicBlock():
    """
    Basic Block from Static Single Assignment (SSA) normal form of code.

    :ivar label: label for debug purposes
    :ivar predecessors: list of block from where the control flow can go to this block
    :ivar phis: list of phi functions which are selecting a value for a variable based on predecessor block
    :ivar body: statements of this block
    :ivar successors: an object to keep track of jumps from this block
    :ivar origns: list of objects which contributed to existence of this object
    """

    def __init__(self, ctx: SsaContext, label:str):
        self.ctx = ctx
        self.label = label
        self.predecessors: List[SsaBasicBlock] = []
        self.phis: List[SsaPhi] = []
        self.body: List[SsaInstr] = []
        self.successors = SsaInstrBranch(self)
        self.origins = []

    def appendPhi(self, phi: SsaPhi):
        assert phi.block is None, (phi, phi.block, self)
        # assert not self.body, ("Adding phi if already have instructions", self, phi)
        phi.block = self
        self.phis.append(phi)

    def insertPhi(self, index: int, phi: SsaPhi):
        assert phi.block is None, (phi, phi.block, self)
        phi.block = self
        self.phis.insert(index, phi)

    def appendInstruction(self, instr: SsaInstr):
        assert instr.block is None, (instr, instr.block, self)
        instr.block = self
        self.body.append(instr)

    def insertInstruction(self, index: int, instr: SsaInstr):
        assert instr.block is None, (instr, instr.block, self)
        instr.block = self
        self.body.insert(index, instr)

    def __repr__(self):
        return f"<{self.__class__.__name__:s} {self.label:s}>"
<|endoftext|>


<commit_before>
import html

from .helpers import *
from .track import Track
from .album import Album

class Discography:
    """
    Discography class of Campdown. This class takes in a URL and treats it as a
    Bandcamp discography page. Takes over downloading of files as well as
    fetching of general information which can be used by other modules

    Args:
        url (str): Bandcamp URL to analyse and download from.
        output (str): relative or absolute path to write to.
        request (request): if supplied this given request's content will be
            analysed instead of making a new request to the mandatory URL.
        verbose (bool): sets if status messages and general information
            should be printed. Errors are still printed regardless of this.
        silent (bool): sets if error messages should be hidden.
        short (bool): omits arist and album fields from downloaded track filenames.
        range_length (number): length of ranged requests in bytes.
        art_enabled (bool): if True the Bandcamp page's artwork will be
            downloaded and saved alongside each of the found albums/tracks.
        id3_enabled (bool): if True tracks downloaded will receive new ID3 tags.
    """

    def __init__(self, url, output, request=None, verbose=False, silent=False, short=False, range_length=0, art_enabled=True, id3_enabled=True):
        # Requests and other information can optionally be filled to remove unneccessary
        # operations such as making a request to a URL that has already been fetched
        # by another component.

        self.url = url  # URL to get information from.
        self.output = output

        # Basic information used when writing tracks.
        self.artist = None

        # Queue array to store album tracks in.
        self.queue = []

        # Store the album request object for later reference.
        self.request = request
        self.content = None

        # Base Bandcamp URL.
        self.base_url = None

        # Set if status messages should be printed to the console.
        self.verbose = verbose

        # Set if error messages should be silenced.
        self.silent = silent

        # Set if the filename should be kept short.
        self.short = short

        # Store the length to be used for ranged requests.
        self.range_length = range_length

        # Set if the cover should be downloaded as well.
        self.art_enabled = art_enabled

        # Set if ID3 tags should be written to files.
        self.id3_enabled = id3_enabled

    def prepare(self):
        """
        Prepares the discography class by gathering information about albums and
        tracks. If no previous request was made and supplied during instantiation
        one will be made at this point. This process does not require making
        requests to the album and track URLs.
        """

        if not valid_url(self.url):  # Validate the URL
            print("The supplied URL is not a valid URL.")
            return False

        if not self.request:
            # Make a request to the album URL.
            self.request = safe_get(self.url)

        if self.request.status_code != 200:
            print("An error occurred while trying to access your supplied URL. Status code: {}".format(
                self.request.status_code))

            self.request = None

            return False

        # Get the content from the request and decode it correctly.
        self.content = self.request.content.decode('utf-8')

        # Verify that this is an discography page.
        if not page_type(self.content) == "discography":
            print("The supplied URL is not a discography page.")

        # Retrieve the base page URL.
        self.base_url = "{}//{}".format(str(self.url).split("/")[
            0], str(self.url).split("/")[2])

        meta = html.unescape(string_between(self.content, '<meta name="Description" content="', ">")).strip()
        self.artist = meta.split("\n", 1)[0]

        if self.artist:
            self.output = os.path.join(self.output, self.artist, "")

            # Create a new artist folder if it doesn't already exist.
            if not os.path.exists(self.output):
                os.makedirs(self.output)

            safe_print(
                '\nSet "{}" as the working directory.'.format(self.output))

        # Make the artist name safe for file writing.
        self.artist = safe_filename(self.artist)

        tracks = [i for i in range(
            len(self.content)) if self.content.startswith('<a href="/track/', i)]

        albums = [i for i in range(
            len(self.content)) if self.content.startswith('<a href="/album/', i)]

        if self.verbose:
            print('\nListing found discography content')

        for i, position in enumerate(albums):
            position += 16  # Add the length of the search string.

            album_name = ""

            while self.content[position] != '"':
                album_name += self.content[position]
                position += 1

            if album_name == "":
                continue

            # Print the prepared track.
            if self.verbose:
                safe_print(self.base_url + "/album/" + album_name)

            # Create a new track instance with the given URL.
            album = Album(self.base_url + "/album/" +
                          album_name,
                          self.output,
                          verbose=self.verbose,
                          silent=self.silent,
                          short=self.short,
                          range_length=self.range_length
                          )

            self.queue.insert(len(self.queue), album)

        for i, position in enumerate(tracks):
            position += 16  # Add the length of the search string.

            track_name = ""

            while self.content[position] != '"':
                track_name += self.content[position]
                position += 1

            if track_name != "":
                # Print the prepared track.
                if self.verbose:
                    safe_print(self.base_url + "/track/" + track_name)

                # Create a new track instance with the given URL.
                track = Track(self.base_url + "/track/" +
                              track_name, self.output, verbose=self.verbose, art_enabled=True)

                self.queue.insert(len(self.queue), track)

        if self.verbose:
            print('\nBeginning downloads. Albums additionally require fetching tracks.')

        return True

    def fetch(self):
        """
        Tells eachs of the queue's items to fetch their individual information
        from their respective Bandcamp pages. This means that requests are made
        to these pages. Requires the queue to be created by the prepare method
        beforehand.
        """

        for i in range(0, len(self.queue)):
            if type(self.queue[i]) is Track:
                self.queue[i].prepare()

            elif type(self.queue[i]) is Album:
                self.queue[i].prepare()
                self.queue[i].fetch()

    def download(self):
        """
        Starts the download process for each of the queue's items. This method
        requires the fetch method to be run beforehand.
        """

        for i in range(0, len(self.queue)):
            if type(self.queue[i]) is Track:
                if self.verbose:
                    safe_print(
                        '\nDownloading track "{}"'.format(self.queue[i].title))

                self.queue[i].download()

            elif type(self.queue[i]) is Album:
                if self.verbose:
                    safe_print(
                        '\nDownloading album "{}"'.format(self.queue[i].title))

                self.queue[i].download()

    def fetch_download(self):
        """
        Starts the download process for each of the queue's items. This method
        is the same as the download and fetch method but chains them together
        to start download files right away instead of preparing them. Good for
        pages with a lot of tracks and albums.
        """

        for i in range(0, len(self.queue)):
            if type(self.queue[i]) is Track:
                self.queue[i].prepare()

                if self.verbose:
                    safe_print(
                        '\nDownloading track "{}"'.format(self.queue[i].title))

                self.queue[i].download()

            elif type(self.queue[i]) is Album:
                self.queue[i].prepare()

                if self.verbose:
                    safe_print(
                        '\nDownloading album "{}"'.format(self.queue[i].title))

                self.queue[i].fetch()
                self.queue[i].download()
<commit_msg>Remove trailing dot in directory names on discography fetches<commit_after>
import html

from .helpers import *
from .track import Track
from .album import Album

class Discography:
    """
    Discography class of Campdown. This class takes in a URL and treats it as a
    Bandcamp discography page. Takes over downloading of files as well as
    fetching of general information which can be used by other modules

    Args:
        url (str): Bandcamp URL to analyse and download from.
        output (str): relative or absolute path to write to.
        request (request): if supplied this given request's content will be
            analysed instead of making a new request to the mandatory URL.
        verbose (bool): sets if status messages and general information
            should be printed. Errors are still printed regardless of this.
        silent (bool): sets if error messages should be hidden.
        short (bool): omits arist and album fields from downloaded track filenames.
        range_length (number): length of ranged requests in bytes.
        art_enabled (bool): if True the Bandcamp page's artwork will be
            downloaded and saved alongside each of the found albums/tracks.
        id3_enabled (bool): if True tracks downloaded will receive new ID3 tags.
    """

    def __init__(self, url, output, request=None, verbose=False, silent=False, short=False, range_length=0, art_enabled=True, id3_enabled=True):
        # Requests and other information can optionally be filled to remove unneccessary
        # operations such as making a request to a URL that has already been fetched
        # by another component.

        self.url = url  # URL to get information from.
        self.output = output

        # Basic information used when writing tracks.
        self.artist = None

        # Queue array to store album tracks in.
        self.queue = []

        # Store the album request object for later reference.
        self.request = request
        self.content = None

        # Base Bandcamp URL.
        self.base_url = None

        # Set if status messages should be printed to the console.
        self.verbose = verbose

        # Set if error messages should be silenced.
        self.silent = silent

        # Set if the filename should be kept short.
        self.short = short

        # Store the length to be used for ranged requests.
        self.range_length = range_length

        # Set if the cover should be downloaded as well.
        self.art_enabled = art_enabled

        # Set if ID3 tags should be written to files.
        self.id3_enabled = id3_enabled

    def prepare(self):
        """
        Prepares the discography class by gathering information about albums and
        tracks. If no previous request was made and supplied during instantiation
        one will be made at this point. This process does not require making
        requests to the album and track URLs.
        """

        if not valid_url(self.url):  # Validate the URL
            print("The supplied URL is not a valid URL.")
            return False

        if not self.request:
            # Make a request to the album URL.
            self.request = safe_get(self.url)

        if self.request.status_code != 200:
            print("An error occurred while trying to access your supplied URL. Status code: {}".format(
                self.request.status_code))

            self.request = None

            return False

        # Get the content from the request and decode it correctly.
        self.content = self.request.content.decode('utf-8')

        # Verify that this is an discography page.
        if not page_type(self.content) == "discography":
            print("The supplied URL is not a discography page.")

        # Retrieve the base page URL.
        self.base_url = "{}//{}".format(str(self.url).split("/")[
            0], str(self.url).split("/")[2])

        meta = html.unescape(string_between(self.content, '<meta name="Description" content="', ">")).strip()
        self.artist = meta.split(".\n", 1)[0]

        if self.artist:
            self.output = os.path.join(self.output, self.artist, "")

            # Create a new artist folder if it doesn't already exist.
            if not os.path.exists(self.output):
                os.makedirs(self.output)

            safe_print(
                '\nSet "{}" as the working directory.'.format(self.output))

        # Make the artist name safe for file writing.
        self.artist = safe_filename(self.artist)

        tracks = [i for i in range(
            len(self.content)) if self.content.startswith('<a href="/track/', i)]

        albums = [i for i in range(
            len(self.content)) if self.content.startswith('<a href="/album/', i)]

        if self.verbose:
            print('\nListing found discography content')

        for i, position in enumerate(albums):
            position += 16  # Add the length of the search string.

            album_name = ""

            while self.content[position] != '"':
                album_name += self.content[position]
                position += 1

            if album_name == "":
                continue

            # Print the prepared track.
            if self.verbose:
                safe_print(self.base_url + "/album/" + album_name)

            # Create a new track instance with the given URL.
            album = Album(
                self.base_url + "/album/" + album_name,
                self.output,
                verbose=self.verbose,
                silent=self.silent,
                short=self.short,
                range_length=self.range_length
            )

            self.queue.insert(len(self.queue), album)

        for i, position in enumerate(tracks):
            position += 16  # Add the length of the search string.

            track_name = ""

            while self.content[position] != '"':
                track_name += self.content[position]
                position += 1

            if track_name != "":
                # Print the prepared track.
                if self.verbose:
                    safe_print(self.base_url + "/track/" + track_name)

                # Create a new track instance with the given URL.
                track = Track(
                    self.base_url + "/track/" + track_name,
                    self.output,
                    verbose=self.verbose,
                    art_enabled=True
                )

                self.queue.insert(len(self.queue), track)

        if self.verbose:
            print('\nBeginning downloads. Albums additionally require fetching tracks.')

        return True

    def fetch(self):
        """
        Tells eachs of the queue's items to fetch their individual information
        from their respective Bandcamp pages. This means that requests are made
        to these pages. Requires the queue to be created by the prepare method
        beforehand.
        """

        for i in range(0, len(self.queue)):
            if type(self.queue[i]) is Track:
                self.queue[i].prepare()

            elif type(self.queue[i]) is Album:
                self.queue[i].prepare()
                self.queue[i].fetch()

    def download(self):
        """
        Starts the download process for each of the queue's items. This method
        requires the fetch method to be run beforehand.
        """

        for i in range(0, len(self.queue)):
            if type(self.queue[i]) is Track:
                if self.verbose:
                    safe_print(
                        '\nDownloading track "{}"'.format(self.queue[i].title))

                self.queue[i].download()

            elif type(self.queue[i]) is Album:
                if self.verbose:
                    safe_print(
                        '\nDownloading album "{}"'.format(self.queue[i].title))

                self.queue[i].download()

    def fetch_download(self):
        """
        Starts the download process for each of the queue's items. This method
        is the same as the download and fetch method but chains them together
        to start download files right away instead of preparing them. Good for
        pages with a lot of tracks and albums.
        """

        for i in range(0, len(self.queue)):
            if type(self.queue[i]) is Track:
                self.queue[i].prepare()

                if self.verbose:
                    safe_print(
                        '\nDownloading track "{}"'.format(self.queue[i].title))

                self.queue[i].download()

            elif type(self.queue[i]) is Album:
                self.queue[i].prepare()

                if self.verbose:
                    safe_print(
                        '\nDownloading album "{}"'.format(self.queue[i].title))

                self.queue[i].fetch()
                self.queue[i].download()
<|endoftext|>


<commit_before>from __future__ import absolute_import, division, print_function, unicode_literals

from six import python_2_unicode_compatible

from canvasapi.canvas_object import CanvasObject
from canvasapi.exceptions import CanvasException, RequiredFieldMissing
from canvasapi.paginated_list import PaginatedList
from canvasapi.progress import Progress
from canvasapi.submission import Submission
from canvasapi.upload import Uploader
from canvasapi.user import User
from canvasapi.user import UserDisplay
from canvasapi.util import combine_kwargs, obj_or_id

@python_2_unicode_compatible
class Assignment(CanvasObject):

    def __str__(self):
        return "{} ({})".format(self.name, self.id)

    def delete(self, **kwargs):
        """
        Delete this assignment.

        :calls: `DELETE /api/v1/courses/:course_id/assignments/:id \
        <https://canvas.instructure.com/doc/api/assignments.html#method.assignments.destroy>`_

        :rtype: :class:`canvasapi.assignment.Assignment`
        """
        response = self._requester.request(
            'DELETE',
            'courses/{}/assignments/{}'.format(self.course_id, self.id),
            _kwargs=combine_kwargs(**kwargs)
        )
        return Assignment(self._requester, response.json())

    def edit(self, **kwargs):
        """
        Modify this assignment.

        :calls: `PUT /api/v1/courses/:course_id/assignments/:id \
        <https://canvas.instructure.com/doc/api/assignments.html#method.assignments_api.update>`_

        :rtype: :class:`canvasapi.assignment.Assignment`
        """
        response = self._requester.request(
            'PUT',
            'courses/{}/assignments/{}'.format(self.course_id, self.id),
            _kwargs=combine_kwargs(**kwargs)
        )

        if 'name' in response.json():
            super(Assignment, self).set_attributes(response.json())

        return Assignment(self._requester, response.json())

    def get_gradeable_students(self, **kwargs):
        """
        List students eligible to submit the assignment.

        :calls: `GET /api/v1/courses/:course_id/assignments/:assignment_id/gradeable_students  \
        <https://canvas.instructure.com/doc/api/submissions.html#method.submissions_api.gradeable_students>`_

        :rtype: :class:`canvasapi.paginated_list.PaginatedList` of
            :class:`canvasapi.user.UserDisplay`
        """
        return PaginatedList(
            UserDisplay,
            self._requester,
            'GET',
            'courses/{}/assignments/{}/gradeable_students'.format(self.course_id, self.id),
            _kwargs=combine_kwargs(**kwargs)
        )

    def get_submission(self, user, **kwargs):
        """
        Get a single submission, based on user id.

        :calls: `GET /api/v1/courses/:course_id/assignments/:assignment_id/submissions/:user_id \
        <https://canvas.instructure.com/doc/api/submissions.html#method.submissions_api.show>`_

        :param user: The object or ID of the related user
        :type user: :class:`canvasapi.user.User` or int

        :rtype: :class:`canvasapi.submission.Submission`
        """
        user_id = obj_or_id(user, "user", (User,))

        response = self._requester.request(
            'GET',
            'courses/{}/assignments/{}/submissions/{}'.format(self.course_id, self.id, user_id),
            _kwargs=combine_kwargs(**kwargs)
        )
        response_json = response.json()
        response_json.update(course_id=self.course_id)

        return Submission(self._requester, response_json)

    def get_submissions(self, **kwargs):
        """
        Get all existing submissions for this assignment.

        :calls: `GET /api/v1/courses/:course_id/assignments/:assignment_id/submissions  \
        <https://canvas.instructure.com/doc/api/submissions.html#method.submissions_api.index>`_

        :rtype: :class:`canvasapi.paginated_list.PaginatedList` of
            :class:`canvasapi.submission.Submission`
        """
        return PaginatedList(
            Submission,
            self._requester,
            'GET',
            'courses/{}/assignments/{}/submissions'.format(self.course_id, self.id),
            {'course_id': self.course_id},
            _kwargs=combine_kwargs(**kwargs)
        )

    def submit(self, submission, file=None, **kwargs):
        """
        Makes a submission for an assignment.

        :calls: `POST /api/v1/courses/:course_id/assignments/:assignment_id/submissions \
        <https://canvas.instructure.com/doc/api/submissions.html#method.submissions.create>`_

        :param submission: The attributes of the submission.
        :type submission: dict
        :param file: A file to upload with the submission. (Optional,
            defaults to `None`. Submission type must be `online_upload`)
        :type file: file or str

        :rtype: :class:`canvasapi.submission.Submission`
        """
        if isinstance(submission, dict) and 'submission_type' in submission:
            kwargs['submission'] = submission
        else:
            raise RequiredFieldMissing(
                "Dictionary with key 'submission_type' is required."
            )

        if file:
            if submission.get('submission_type') != 'online_upload':
                raise ValueError(
                    "To upload a file, `submission['submission_type']` must be `online_upload`."
                )

            upload_response = self.upload_to_submission(file, **kwargs)
            if upload_response[0]:
                kwargs['submission']['file_ids'] = [upload_response[1]['id']]
            else:
                raise CanvasException(
                    'File upload failed. Not submitting.'.format()
                )

        response = self._requester.request(
            'POST',
            'courses/{}/assignments/{}/submissions'.format(self.course_id, self.id),
            _kwargs=combine_kwargs(**kwargs)
        )
        response_json = response.json()
        response_json.update(course_id=self.course_id)

        return Submission(self._requester, response_json)

    def submissions_bulk_update(self, **kwargs):
        """
        Update the grading and comments on multiple student's assignment
        submissions in an asynchronous job.

        :calls: `POST /api/v1/courses/:course_id/assignments/:assignment_id/ \
            submissions/update_grades \
        <https://canvas.instructure.com/doc/api/submissions.html#method.submissions_api.bulk_update>`_

        :rtype: :class:`canvasapi.progress.Progress`
        """
        response = self._requester.request(
            'POST',
            'courses/{}/assignments/{}/submissions/update_grades'.format(
                self.course_id,
                self.id
            ),
            _kwargs=combine_kwargs(**kwargs)
        )
        return Progress(self._requester, response.json())

    def upload_to_submission(self, file, user='self', **kwargs):
        """
        Upload a file to a submission.

        :calls: `POST /api/v1/courses/:course_id/assignments/:assignment_id/ \
            submissions/:user_id/files \
        <https://canvas.instructure.com/doc/api/submissions.html#method.submissions_api.create_file>`_

        :param file: The file or path of the file to upload.
        :type file: file or str
        :param user: The object or ID of the related user, or 'self' for the
            current user. Defaults to 'self'.
        :type user: :class:`canvasapi.user.User`, int, or str

        :returns: True if the file uploaded successfully, False otherwise, \
                    and the JSON response from the API.
        :rtype: tuple
        """
        user_id = obj_or_id(user, "user", (User,))

        return Uploader(
            self._requester,
            'courses/{}/assignments/{}/submissions/{}/files'.format(
                self.course_id,
                self.id,
                user_id
            ),
            file,
            **kwargs
        ).start()

@python_2_unicode_compatible
class AssignmentGroup(CanvasObject):

    def __str__(self):
        return "{} ({})".format(self.name, self.id)

    def edit(self, **kwargs):
        """
        Modify this assignment group.

        :calls: `PUT /api/v1/courses/:course_id/assignment_groups/:assignment_group_id \
        <https://canvas.instructure.com/doc/api/assignment_groups.html#method.assignment_groups_api.update>`_

        :rtype: :class:`canvasapi.assignment.AssignmentGroup`
        """
        response = self._requester.request(
            'PUT',
            'courses/{}/assignment_groups/{}'.format(self.course_id, self.id),
            _kwargs=combine_kwargs(**kwargs)
        )

        if 'name' in response.json():
            super(AssignmentGroup, self).set_attributes(response.json())

        return AssignmentGroup(self._requester, response.json())

    def delete(self, **kwargs):
        """
        Delete this assignment.

        :calls: `DELETE /api/v1/courses/:course_id/assignment_groups/:assignment_group_id \
        <https://canvas.instructure.com/doc/api/assignment_groups.html#method.assignment_groups_api.destroy>`_

        :rtype: :class:`canvasapi.assignment.AssignmentGroup`
        """
        response = self._requester.request(
            'DELETE',
            'courses/{}/assignment_groups/{}'.format(self.course_id, self.id),
            _kwargs=combine_kwargs(**kwargs)
        )
        return AssignmentGroup(self._requester, response.json())
<commit_msg>Remove unnecessary format call<commit_after>from __future__ import absolute_import, division, print_function, unicode_literals

from six import python_2_unicode_compatible

from canvasapi.canvas_object import CanvasObject
from canvasapi.exceptions import CanvasException, RequiredFieldMissing
from canvasapi.paginated_list import PaginatedList
from canvasapi.progress import Progress
from canvasapi.submission import Submission
from canvasapi.upload import Uploader
from canvasapi.user import User
from canvasapi.user import UserDisplay
from canvasapi.util import combine_kwargs, obj_or_id

@python_2_unicode_compatible
class Assignment(CanvasObject):

    def __str__(self):
        return "{} ({})".format(self.name, self.id)

    def delete(self, **kwargs):
        """
        Delete this assignment.

        :calls: `DELETE /api/v1/courses/:course_id/assignments/:id \
        <https://canvas.instructure.com/doc/api/assignments.html#method.assignments.destroy>`_

        :rtype: :class:`canvasapi.assignment.Assignment`
        """
        response = self._requester.request(
            'DELETE',
            'courses/{}/assignments/{}'.format(self.course_id, self.id),
            _kwargs=combine_kwargs(**kwargs)
        )
        return Assignment(self._requester, response.json())

    def edit(self, **kwargs):
        """
        Modify this assignment.

        :calls: `PUT /api/v1/courses/:course_id/assignments/:id \
        <https://canvas.instructure.com/doc/api/assignments.html#method.assignments_api.update>`_

        :rtype: :class:`canvasapi.assignment.Assignment`
        """
        response = self._requester.request(
            'PUT',
            'courses/{}/assignments/{}'.format(self.course_id, self.id),
            _kwargs=combine_kwargs(**kwargs)
        )

        if 'name' in response.json():
            super(Assignment, self).set_attributes(response.json())

        return Assignment(self._requester, response.json())

    def get_gradeable_students(self, **kwargs):
        """
        List students eligible to submit the assignment.

        :calls: `GET /api/v1/courses/:course_id/assignments/:assignment_id/gradeable_students  \
        <https://canvas.instructure.com/doc/api/submissions.html#method.submissions_api.gradeable_students>`_

        :rtype: :class:`canvasapi.paginated_list.PaginatedList` of
            :class:`canvasapi.user.UserDisplay`
        """
        return PaginatedList(
            UserDisplay,
            self._requester,
            'GET',
            'courses/{}/assignments/{}/gradeable_students'.format(self.course_id, self.id),
            _kwargs=combine_kwargs(**kwargs)
        )

    def get_submission(self, user, **kwargs):
        """
        Get a single submission, based on user id.

        :calls: `GET /api/v1/courses/:course_id/assignments/:assignment_id/submissions/:user_id \
        <https://canvas.instructure.com/doc/api/submissions.html#method.submissions_api.show>`_

        :param user: The object or ID of the related user
        :type user: :class:`canvasapi.user.User` or int

        :rtype: :class:`canvasapi.submission.Submission`
        """
        user_id = obj_or_id(user, "user", (User,))

        response = self._requester.request(
            'GET',
            'courses/{}/assignments/{}/submissions/{}'.format(self.course_id, self.id, user_id),
            _kwargs=combine_kwargs(**kwargs)
        )
        response_json = response.json()
        response_json.update(course_id=self.course_id)

        return Submission(self._requester, response_json)

    def get_submissions(self, **kwargs):
        """
        Get all existing submissions for this assignment.

        :calls: `GET /api/v1/courses/:course_id/assignments/:assignment_id/submissions  \
        <https://canvas.instructure.com/doc/api/submissions.html#method.submissions_api.index>`_

        :rtype: :class:`canvasapi.paginated_list.PaginatedList` of
            :class:`canvasapi.submission.Submission`
        """
        return PaginatedList(
            Submission,
            self._requester,
            'GET',
            'courses/{}/assignments/{}/submissions'.format(self.course_id, self.id),
            {'course_id': self.course_id},
            _kwargs=combine_kwargs(**kwargs)
        )

    def submit(self, submission, file=None, **kwargs):
        """
        Makes a submission for an assignment.

        :calls: `POST /api/v1/courses/:course_id/assignments/:assignment_id/submissions \
        <https://canvas.instructure.com/doc/api/submissions.html#method.submissions.create>`_

        :param submission: The attributes of the submission.
        :type submission: dict
        :param file: A file to upload with the submission. (Optional,
            defaults to `None`. Submission type must be `online_upload`)
        :type file: file or str

        :rtype: :class:`canvasapi.submission.Submission`
        """
        if isinstance(submission, dict) and 'submission_type' in submission:
            kwargs['submission'] = submission
        else:
            raise RequiredFieldMissing(
                "Dictionary with key 'submission_type' is required."
            )

        if file:
            if submission.get('submission_type') != 'online_upload':
                raise ValueError(
                    "To upload a file, `submission['submission_type']` must be `online_upload`."
                )

            upload_response = self.upload_to_submission(file, **kwargs)
            if upload_response[0]:
                kwargs['submission']['file_ids'] = [upload_response[1]['id']]
            else:
                raise CanvasException('File upload failed. Not submitting.')

        response = self._requester.request(
            'POST',
            'courses/{}/assignments/{}/submissions'.format(self.course_id, self.id),
            _kwargs=combine_kwargs(**kwargs)
        )
        response_json = response.json()
        response_json.update(course_id=self.course_id)

        return Submission(self._requester, response_json)

    def submissions_bulk_update(self, **kwargs):
        """
        Update the grading and comments on multiple student's assignment
        submissions in an asynchronous job.

        :calls: `POST /api/v1/courses/:course_id/assignments/:assignment_id/ \
            submissions/update_grades \
        <https://canvas.instructure.com/doc/api/submissions.html#method.submissions_api.bulk_update>`_

        :rtype: :class:`canvasapi.progress.Progress`
        """
        response = self._requester.request(
            'POST',
            'courses/{}/assignments/{}/submissions/update_grades'.format(
                self.course_id,
                self.id
            ),
            _kwargs=combine_kwargs(**kwargs)
        )
        return Progress(self._requester, response.json())

    def upload_to_submission(self, file, user='self', **kwargs):
        """
        Upload a file to a submission.

        :calls: `POST /api/v1/courses/:course_id/assignments/:assignment_id/ \
            submissions/:user_id/files \
        <https://canvas.instructure.com/doc/api/submissions.html#method.submissions_api.create_file>`_

        :param file: The file or path of the file to upload.
        :type file: file or str
        :param user: The object or ID of the related user, or 'self' for the
            current user. Defaults to 'self'.
        :type user: :class:`canvasapi.user.User`, int, or str

        :returns: True if the file uploaded successfully, False otherwise, \
                    and the JSON response from the API.
        :rtype: tuple
        """
        user_id = obj_or_id(user, "user", (User,))

        return Uploader(
            self._requester,
            'courses/{}/assignments/{}/submissions/{}/files'.format(
                self.course_id,
                self.id,
                user_id
            ),
            file,
            **kwargs
        ).start()

@python_2_unicode_compatible
class AssignmentGroup(CanvasObject):

    def __str__(self):
        return "{} ({})".format(self.name, self.id)

    def edit(self, **kwargs):
        """
        Modify this assignment group.

        :calls: `PUT /api/v1/courses/:course_id/assignment_groups/:assignment_group_id \
        <https://canvas.instructure.com/doc/api/assignment_groups.html#method.assignment_groups_api.update>`_

        :rtype: :class:`canvasapi.assignment.AssignmentGroup`
        """
        response = self._requester.request(
            'PUT',
            'courses/{}/assignment_groups/{}'.format(self.course_id, self.id),
            _kwargs=combine_kwargs(**kwargs)
        )

        if 'name' in response.json():
            super(AssignmentGroup, self).set_attributes(response.json())

        return AssignmentGroup(self._requester, response.json())

    def delete(self, **kwargs):
        """
        Delete this assignment.

        :calls: `DELETE /api/v1/courses/:course_id/assignment_groups/:assignment_group_id \
        <https://canvas.instructure.com/doc/api/assignment_groups.html#method.assignment_groups_api.destroy>`_

        :rtype: :class:`canvasapi.assignment.AssignmentGroup`
        """
        response = self._requester.request(
            'DELETE',
            'courses/{}/assignment_groups/{}'.format(self.course_id, self.id),
            _kwargs=combine_kwargs(**kwargs)
        )
        return AssignmentGroup(self._requester, response.json())
<|endoftext|>


<commit_before>__version__ = '0.0.1'
<commit_msg>Bump version<commit_after>__version__ = '0.1'
<|endoftext|>


<commit_before>__version__ = '1.0.3'
<commit_msg>Set dev version<commit_after>__version__ = '1.0.3.dev'
<|endoftext|>