<commit_before>from test_plus.test import TestCase

from ..views import FeedServiceList
from ..views import ServiceDetail
from ..views import UserServiceList
from ..serializers import ServiceSerializer

from rest_framework.test import force_authenticate
from rest_framework.test import APIRequestFactory

from django.contrib.gis.geos import Point
from django.conf import settings
from django.urls import reverse

from semillas_backend.users.factory import UserFactory
from services.factory import ServiceFactory, CategoryFactory
from services.factory import categories

from services.models import Service, Category
from semillas_backend.users.models import User

class BaseServiceTestCase(TestCase):

    def setUp(self):
        self.factory = APIRequestFactory()

class TestFeedServiceList(BaseServiceTestCase):

    # def tearDown(self):
    #    Category.objects.all().delete()

    def setUp(self):
        # call BaseServiceTestCase.setUp()
        super(TestFeedServiceList, self).setUp()

        # Instantiate the view directly. Never do this outside a test!
        self.view = FeedServiceList()

        # Create self.users, Services & Categories for test cases
        self.users = UserFactory.create_batch(size=5)
        self.services = ServiceFactory.create_batch(
            size=5,
            category=Category.objects.first()
        )

        # Assign each service to 1 of the self.users
        self.services[0].author = self.users[0]
        self.services[0].title = "1"
        self.services[0].description = "testing"
        self.services[0].save()
        self.services[1].author = self.users[1]
        self.services[1].title = "2"
        self.services[1].description = "testing"
        self.services[1].save()
        self.services[2].author = self.users[2]
        self.services[2].title = "3"
        self.services[2].description = "testing"
        self.services[2].save()
        self.services[3].author = self.users[3]
        self.services[3].title = "4"
        self.services[3].description = "testing"
        self.services[3].save()
        self.services[4].author = self.users[4]
        self.services[4].title = "5"
        self.services[4].description = "testing"
        self.services[4].save()

    def test_response_check_distances_saved_in_user(self):
        """ This tests ask the feed without lat and lon and expects
        the lat and lon are retrieved from user model saved in db
        """

        # Create some locations
        location_madrid = Point(-3.8196228, 40.4378698)  # Madrid 0
        location_paris = Point(2.3488, 48.8534)  # Paris 1
        location_london = Point(-0.3817834, 51.528308)  # London 2
        location_berlin = Point(13.4105, 52.5244)  # Berlin 3
        location_rome = Point(12.395912, 41.909986)  # Rome 4

        # Update locations on each of the self.users
        self.users[0].location = location_madrid
        self.users[0].save()
        self.users[1].location = location_paris
        self.users[1].save()
        self.users[2].location = location_london
        self.users[2].save()
        self.users[3].location = location_berlin
        self.users[3].save()
        self.users[4].location = location_rome
        self.users[4].save()

        # Generate a request search for "testing" key word
        request = self.factory.get('/api/v1/service/feed?search=')
        # Attach the user to the request
        force_authenticate(request, user=self.users[3])
        #request.user = self.users[3]

        self.view = FeedServiceList.as_view()
        response = self.view(request)

        # Expect: expect queryset of services ordered by proximity
        #   self.make_user()
        self.assertEqual(
            response.status_code,
            200
        )

        self.assertIsInstance(
            response.data,
            list
        )

        self.assertEqual(
            [item["title"] for item in response.data],
            ["4", "2", "3", "5", "1"]
        )

    def test_response_check_distances_anonymous_user_sending_params(self):
        """ This tests ask the feed without lat and lon and expects
        the lat and lon are retrieved from user model saved in db
        """

        # Create some locations
        location_madrid = Point(-3.8196228, 40.4378698)  # Madrid 0
        location_paris = Point(2.3488, 48.8534)  # Paris 1
        location_london = Point(-0.3817834, 51.528308)  # London 2
        location_berlin = Point(13.4105, 52.5244)  # Berlin 3
        location_rome = Point(12.395912, 41.909986)  # Rome 4

        # Update locations on each of the self.users
        self.users[0].location = location_madrid
        self.users[0].save()
        self.users[1].location = location_paris
        self.users[1].save()
        self.users[2].location = location_london
        self.users[2].save()
        self.users[3].location = location_berlin
        self.users[3].save()
        self.users[4].location = location_rome
        self.users[4].save()

        # Generate a request search for "testing" key word
        request = self.factory.get(
            '/api/v1/service/feed?lat=%s&lon=%s' % (
                location_berlin.coords[1],
                location_berlin.coords[0]))

        self.view = FeedServiceList.as_view()
        response = self.view(request)

        # Expect: expect queryset of services ordered by proximity
        #   self.make_user()
        self.assertEqual(
            response.status_code,
            200
        )

        self.assertIsInstance(
            response.data,
            list
        )

        self.assertEqual(
            [item["title"] for item in response.data],
            ["4", "2", "3", "5", "1"]
        )

    def test_response_check_distances_signed_in_user_sending_params(self):
        """ This tests ask the feed without lat and lon and expects
        the lat and lon are retrieved from user model saved in db
        """

        # Create some locations
        location_madrid = Point(-3.8196228, 40.4378698)  # Madrid 0
        location_paris = Point(2.3488, 48.8534)  # Paris 1
        location_london = Point(-0.3817834, 51.528308)  # London 2
        location_berlin = Point(13.4105, 52.5244)  # Berlin 3
        location_rome = Point(12.395912, 41.909986)  # Rome 4

        # Update locations on each of the self.users
        self.users[0].location = location_madrid
        self.users[0].save()
        self.users[1].location = location_paris
        self.users[1].save()
        self.users[2].location = location_london
        self.users[2].save()
        self.users[3].location = location_berlin
        self.users[3].save()
        self.users[4].location = location_rome
        self.users[4].save()

        # Generate a request search for "testing" key word
        request = self.factory.get(
            '/api/v1/service/feed?lat=%s&lon=%s' % (
                location_rome.coords[1],
                location_rome.coords[0]))

        # Attach the user to the request
        force_authenticate(request, user=self.users[3])

        self.view = FeedServiceList.as_view()
        response = self.view(request)

        # Expect: expect queryset of services ordered by proximity
        #   self.make_user()
        self.assertEqual(
            response.status_code,
            200
        )

        self.assertIsInstance(
            response.data,
            list
        )

        self.assertEqual(
            [item["title"] for item in response.data],
            ["4", "5", "2", "1", "3"]
        )

        # check the user location is updated
        self.users[3] = User.objects.get(id=self.users[3].id)
        self.assertEqual(location_rome.coords, self.users[3].location.coords)

    def test_category_filtering(self):
        Service.objects.all().update(category=Category.objects.first())
        serv = Service.objects.first()
        serv.category = Category.objects.last()
        cat = Category.objects.last()
        serv.save()
        # Generate a request search for "testing" key word
        request = self.factory.get('/api/v1/service/feed?category='+str(cat.id))
        # Attach the user to the request
        force_authenticate(request, user=self.users[3])

        self.view = FeedServiceList.as_view()
        response = self.view(request)

        # Expect: expect queryset of services ordered by proximity
        #   self.make_user()
        self.assertEqual(
            len(response.data),
            1
        )

        self.assertEqual(
            response.status_code,
            200
        )

    def test_wrong_category(self):
        # Generate a request search for "testing" key word
        request = self.factory.get('/api/v1/service/feed?category=2000000')
        # Attach the user to the request
        force_authenticate(request, user=self.users[3])

        self.view = FeedServiceList.as_view()
        response = self.view(request)

        # Expect: expect queryset of services ordered by proximity
        #   self.make_user()
        self.assertEqual(
            response.status_code,
            200
        )

        self.assertEqual(
            len(response.data),
            0
        )

    def test_text_search_filtering(self):
        Service.objects.all().update(category=Category.objects.first())
        serv = Service.objects.first()
        serv.title = 'wordtobesearched'
        serv.save()
        # Generate a request search for "testing" key word
        request = self.factory.get('/api/v1/service/feed?search=wordtobesearched')
        # Attach the user to the request
        force_authenticate(request, user=self.users[3])

        self.view = FeedServiceList.as_view()
        response = self.view(request)

        # Expect: expect queryset of services ordered by proximity
        #   self.make_user()
        self.assertEqual(
            len(response.data),
            1
        )
        self.assertEqual(
            response.status_code,
            200
        )

    def test_user_services(self):
        """ This tests ask for all the services of a user
        """
        # Generate a request search for "testing" key word
        request = self.factory.get(reverse('api_users:list',
                                           kwargs={'uuid': self.users[1]}))
        # Attach the user to the request
        force_authenticate(request, user=self.users[3])
        #request.user = self.users[3]

        self.view = UserServiceList.as_view()
        response = self.view(request)

        # Expect: expect queryset of services ordered by proximity
        #   self.make_user()
        self.assertEqual(
            response.status_code,
            200
        )

        self.assertIsInstance(
            response.data,
            list
        )

        self.assertEqual(
            [item["title"] for item in response.data],
            ["3"]
        )

class TestServiceDetail(BaseServiceTestCase):

    # def tearDown(self):
    #    Category.objects.all().delete()

    def setUp(self):
        # call BaseServiceTestCase.setUp()
        super(TestServiceDetail, self).setUp()

        location_madrid = Point(-3.8196228, 40.4378698)  # Madrid 0
        location_paris = Point(2.3488, 48.8534)  # Paris 1

        # Create self.users, Services & Categories for test cases
        self.user = UserFactory(location=location_madrid)
        self.owner = UserFactory(location=location_paris)
        self.service = ServiceFactory(
            category=Category.objects.first(),
            author=self.owner,
            title='1',
        )

    def test_service_detail_get_with_distance(self):
        Service.objects.all().update(category=Category.objects.first())
        serv = Service.objects.first()

        factory = APIRequestFactory()
        request = factory.get('/api/v1/service/{0}/'.format(serv.uuid))
        view = ServiceDetail.as_view()
        force_authenticate(request, user=self.user)
        response = view(request, uuid=serv.uuid)
        self.assertEqual(
            response.data['uuid'],
            str(serv.uuid)
        )

        self.assertEqual(
            response.data['distance'],
            1043.4
        )

        self.assertEqual(
            response.status_code,
            200
        )

    def test_service_detail_get_anonymous_user(self):
        Service.objects.all().update(category=Category.objects.first())
        serv = Service.objects.first()

        response = self.client.get('/api/v1/service/{0}/'.format(serv.uuid))
        # Expect: expect queryset of services ordered by proximity
        #   self.make_user()
        self.assertEqual(
            response.data['uuid'],
            str(serv.uuid)
        )
        self.assertEqual(
            response.status_code,
            200
        )

    def test_service_detail_with_no_photos(self):
        serv = ServiceFactory(
            category=Category.objects.first(),
            author=self.owner,
            title='1',
        )
        serv.photos.all().delete()

        photos = ServiceSerializer(serv).data['photos']
        self.assertEqual(
            photos[0]['photo'],
            '/media/' + settings.SERVICE_PLACEHOLDER_PHOTO
        )
<commit_msg>Fix typo in test<commit_after>from test_plus.test import TestCase

from ..views import FeedServiceList
from ..views import ServiceDetail
from ..views import UserServiceList
from ..serializers import ServiceSerializer

from rest_framework.test import force_authenticate
from rest_framework.test import APIRequestFactory

from django.contrib.gis.geos import Point
from django.conf import settings
from django.urls import reverse

from semillas_backend.users.factory import UserFactory
from services.factory import ServiceFactory, CategoryFactory
from services.factory import categories

from services.models import Service, Category
from semillas_backend.users.models import User

class BaseServiceTestCase(TestCase):

    def setUp(self):
        self.factory = APIRequestFactory()

class TestFeedServiceList(BaseServiceTestCase):

    # def tearDown(self):
    #    Category.objects.all().delete()

    def setUp(self):
        # call BaseServiceTestCase.setUp()
        super(TestFeedServiceList, self).setUp()

        # Instantiate the view directly. Never do this outside a test!
        self.view = FeedServiceList()

        # Create self.users, Services & Categories for test cases
        self.users = UserFactory.create_batch(size=5)
        self.services = ServiceFactory.create_batch(
            size=5,
            category=Category.objects.first()
        )

        # Assign each service to 1 of the self.users
        self.services[0].author = self.users[0]
        self.services[0].title = "1"
        self.services[0].description = "testing"
        self.services[0].save()
        self.services[1].author = self.users[1]
        self.services[1].title = "2"
        self.services[1].description = "testing"
        self.services[1].save()
        self.services[2].author = self.users[2]
        self.services[2].title = "3"
        self.services[2].description = "testing"
        self.services[2].save()
        self.services[3].author = self.users[3]
        self.services[3].title = "4"
        self.services[3].description = "testing"
        self.services[3].save()
        self.services[4].author = self.users[4]
        self.services[4].title = "5"
        self.services[4].description = "testing"
        self.services[4].save()

    def test_response_check_distances_saved_in_user(self):
        """ This tests ask the feed without lat and lon and expects
        the lat and lon are retrieved from user model saved in db
        """

        # Create some locations
        location_madrid = Point(-3.8196228, 40.4378698)  # Madrid 0
        location_paris = Point(2.3488, 48.8534)  # Paris 1
        location_london = Point(-0.3817834, 51.528308)  # London 2
        location_berlin = Point(13.4105, 52.5244)  # Berlin 3
        location_rome = Point(12.395912, 41.909986)  # Rome 4

        # Update locations on each of the self.users
        self.users[0].location = location_madrid
        self.users[0].save()
        self.users[1].location = location_paris
        self.users[1].save()
        self.users[2].location = location_london
        self.users[2].save()
        self.users[3].location = location_berlin
        self.users[3].save()
        self.users[4].location = location_rome
        self.users[4].save()

        # Generate a request search for "testing" key word
        request = self.factory.get('/api/v1/service/feed?search=')
        # Attach the user to the request
        force_authenticate(request, user=self.users[3])
        #request.user = self.users[3]

        self.view = FeedServiceList.as_view()
        response = self.view(request)

        # Expect: expect queryset of services ordered by proximity
        #   self.make_user()
        self.assertEqual(
            response.status_code,
            200
        )

        self.assertIsInstance(
            response.data,
            list
        )

        self.assertEqual(
            [item["title"] for item in response.data],
            ["4", "2", "3", "5", "1"]
        )

    def test_response_check_distances_anonymous_user_sending_params(self):
        """ This tests ask the feed without lat and lon and expects
        the lat and lon are retrieved from user model saved in db
        """

        # Create some locations
        location_madrid = Point(-3.8196228, 40.4378698)  # Madrid 0
        location_paris = Point(2.3488, 48.8534)  # Paris 1
        location_london = Point(-0.3817834, 51.528308)  # London 2
        location_berlin = Point(13.4105, 52.5244)  # Berlin 3
        location_rome = Point(12.395912, 41.909986)  # Rome 4

        # Update locations on each of the self.users
        self.users[0].location = location_madrid
        self.users[0].save()
        self.users[1].location = location_paris
        self.users[1].save()
        self.users[2].location = location_london
        self.users[2].save()
        self.users[3].location = location_berlin
        self.users[3].save()
        self.users[4].location = location_rome
        self.users[4].save()

        # Generate a request search for "testing" key word
        request = self.factory.get(
            '/api/v1/service/feed?lat=%s&lon=%s' % (
                location_berlin.coords[1],
                location_berlin.coords[0]))

        self.view = FeedServiceList.as_view()
        response = self.view(request)

        # Expect: expect queryset of services ordered by proximity
        #   self.make_user()
        self.assertEqual(
            response.status_code,
            200
        )

        self.assertIsInstance(
            response.data,
            list
        )

        self.assertEqual(
            [item["title"] for item in response.data],
            ["4", "2", "3", "5", "1"]
        )

    def test_response_check_distances_signed_in_user_sending_params(self):
        """ This tests ask the feed without lat and lon and expects
        the lat and lon are retrieved from user model saved in db
        """

        # Create some locations
        location_madrid = Point(-3.8196228, 40.4378698)  # Madrid 0
        location_paris = Point(2.3488, 48.8534)  # Paris 1
        location_london = Point(-0.3817834, 51.528308)  # London 2
        location_berlin = Point(13.4105, 52.5244)  # Berlin 3
        location_rome = Point(12.395912, 41.909986)  # Rome 4

        # Update locations on each of the self.users
        self.users[0].location = location_madrid
        self.users[0].save()
        self.users[1].location = location_paris
        self.users[1].save()
        self.users[2].location = location_london
        self.users[2].save()
        self.users[3].location = location_berlin
        self.users[3].save()
        self.users[4].location = location_rome
        self.users[4].save()

        # Generate a request search for "testing" key word
        request = self.factory.get(
            '/api/v1/service/feed?lat=%s&lon=%s' % (
                location_rome.coords[1],
                location_rome.coords[0]))

        # Attach the user to the request
        force_authenticate(request, user=self.users[3])

        self.view = FeedServiceList.as_view()
        response = self.view(request)

        # Expect: expect queryset of services ordered by proximity
        #   self.make_user()
        self.assertEqual(
            response.status_code,
            200
        )

        self.assertIsInstance(
            response.data,
            list
        )

        self.assertEqual(
            [item["title"] for item in response.data],
            ["4", "5", "2", "1", "3"]
        )

        # check the user location is updated
        self.users[3] = User.objects.get(id=self.users[3].id)
        self.assertEqual(location_rome.coords, self.users[3].location.coords)

    def test_category_filtering(self):
        Service.objects.all().update(category=Category.objects.first())
        serv = Service.objects.first()
        serv.category = Category.objects.last()
        cat = Category.objects.last()
        serv.save()
        # Generate a request search for "testing" key word
        request = self.factory.get('/api/v1/service/feed?category='+str(cat.id))
        # Attach the user to the request
        force_authenticate(request, user=self.users[3])

        self.view = FeedServiceList.as_view()
        response = self.view(request)

        # Expect: expect queryset of services ordered by proximity
        #   self.make_user()
        self.assertEqual(
            len(response.data),
            1
        )

        self.assertEqual(
            response.status_code,
            200
        )

    def test_wrong_category(self):
        # Generate a request search for "testing" key word
        request = self.factory.get('/api/v1/service/feed?category=2000000')
        # Attach the user to the request
        force_authenticate(request, user=self.users[3])

        self.view = FeedServiceList.as_view()
        response = self.view(request)

        # Expect: expect queryset of services ordered by proximity
        #   self.make_user()
        self.assertEqual(
            response.status_code,
            200
        )

        self.assertEqual(
            len(response.data),
            0
        )

    def test_text_search_filtering(self):
        Service.objects.all().update(category=Category.objects.first())
        serv = Service.objects.first()
        serv.title = 'wordtobesearched'
        serv.save()
        # Generate a request search for "testing" key word
        request = self.factory.get('/api/v1/service/feed?search=wordtobesearched')
        # Attach the user to the request
        force_authenticate(request, user=self.users[3])

        self.view = FeedServiceList.as_view()
        response = self.view(request)

        # Expect: expect queryset of services ordered by proximity
        #   self.make_user()
        self.assertEqual(
            len(response.data),
            1
        )
        self.assertEqual(
            response.status_code,
            200
        )

    def test_user_services(self):
        """ This tests ask for all the services of a user
        """
        # Generate a request search for "testing" key word
        request = self.factory.get(reverse('api_users:list',
                                           kwargs={'uuid': self.users[1].uuid}))
        # Attach the user to the request
        force_authenticate(request, user=self.users[3])
        #request.user = self.users[3]

        self.view = UserServiceList.as_view()
        response = self.view(request)

        # Expect: expect queryset of services ordered by proximity
        #   self.make_user()
        self.assertEqual(
            response.status_code,
            200
        )

        self.assertIsInstance(
            response.data,
            list
        )

        self.assertEqual(
            [item["title"] for item in response.data],
            ["3"]
        )

class TestServiceDetail(BaseServiceTestCase):

    # def tearDown(self):
    #    Category.objects.all().delete()

    def setUp(self):
        # call BaseServiceTestCase.setUp()
        super(TestServiceDetail, self).setUp()

        location_madrid = Point(-3.8196228, 40.4378698)  # Madrid 0
        location_paris = Point(2.3488, 48.8534)  # Paris 1

        # Create self.users, Services & Categories for test cases
        self.user = UserFactory(location=location_madrid)
        self.owner = UserFactory(location=location_paris)
        self.service = ServiceFactory(
            category=Category.objects.first(),
            author=self.owner,
            title='1',
        )

    def test_service_detail_get_with_distance(self):
        Service.objects.all().update(category=Category.objects.first())
        serv = Service.objects.first()

        factory = APIRequestFactory()
        request = factory.get('/api/v1/service/{0}/'.format(serv.uuid))
        view = ServiceDetail.as_view()
        force_authenticate(request, user=self.user)
        response = view(request, uuid=serv.uuid)
        self.assertEqual(
            response.data['uuid'],
            str(serv.uuid)
        )

        self.assertEqual(
            response.data['distance'],
            1043.4
        )

        self.assertEqual(
            response.status_code,
            200
        )

    def test_service_detail_get_anonymous_user(self):
        Service.objects.all().update(category=Category.objects.first())
        serv = Service.objects.first()

        response = self.client.get('/api/v1/service/{0}/'.format(serv.uuid))
        # Expect: expect queryset of services ordered by proximity
        #   self.make_user()
        self.assertEqual(
            response.data['uuid'],
            str(serv.uuid)
        )
        self.assertEqual(
            response.status_code,
            200
        )

    def test_service_detail_with_no_photos(self):
        serv = ServiceFactory(
            category=Category.objects.first(),
            author=self.owner,
            title='1',
        )
        serv.photos.all().delete()

        photos = ServiceSerializer(serv).data['photos']
        self.assertEqual(
            photos[0]['photo'],
            '/media/' + settings.SERVICE_PLACEHOLDER_PHOTO
        )
<|endoftext|>


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

from __future__ import absolute_import

"""
JSON bindings for IMS data.

2014 JSON schema:

    {
        "number": 101,                              // int >= 0
        "priority": 3,                              // int {1,3,5}
        "summary": "Diapers, please",               // one line
        "location_address": "8:15 & K",             // one line
        "location_name": "Camp Fishes",             // one line
        "ranger_handles": [
            "Santa Cruz"                            // handle in Clubhouse
        ],
        "incident_types": [
            "Law Enforcement"                       // from list in config
        ],
        "report_entries": [
            {
                "author": "Hot Yogi",               // handle in Clubhouse
                "created": "2014-08-30T21:12:50Z",  // RFC 3339, Zulu
                "system_entry": false,              // boolean
                "text": "Need diapers\nPronto"      // multi-line
            }
        ],
        "timestamp": "2014-08-30T21:38:11Z"         // RFC 3339, Zulu
        "state": "closed",                          // from JSON.state_*
    }

"""

__all__ = [
    "json_from_file",
    "json_from_text",
    "json_as_text",

    "datetime_as_rfc3339",
    "rfc3339_as_datetime",

    "JSON",

    "incident_from_json",
    "incident_as_json",
]

from json import dumps, load as json_from_file, loads as json_from_text
from datetime import (
    datetime as DateTime,  # timedelta as TimeDelta, tzinfo as TZInfo
)

from twisted.python.constants import (
    Values, ValueConstant
)

from .tz import utc
from .data import (
    InvalidDataError, IncidentState, Incident, ReportEntry, Ranger, Location
)

rfc3339_datetime_format = "%Y-%m-%dT%H:%M:%SZ"

def json_as_text(obj):
    """
    Convert an object into JSON text.

    @param obj: An object that is serializable to JSON.
    @type obj: L{object}

    @return: JSON text.
    @rtype: L{unicode}
    """
    return dumps(obj, separators=(',', ':')).decode("UTF-8")

def datetime_as_rfc3339(datetime):
    """
    Convert a date-time object into an RFC 3339 formatted date-time string.

    @param datetime: A non-naive date-time object to convert.
    @type datetime: L{DateTime}

    @return: An RFC 3339 formatted date-time string corresponding to
        C{datetime} (converted to UTC).
    @rtype: L{str}
    """
    if not datetime:
        return None
    else:
        datetime = datetime.astimezone(utc)
        return datetime.strftime(rfc3339_datetime_format)

def rfc3339_as_datetime(rfc3339):
    """
    Convert an RFC 3339 formatted string to a date-time object.

    @param rfc3339: An RFC 3339 formatted string.
    @type rfc3339: L{str}

    @return: An date-time object (in UTC) corresponding to C{rfc3339}.
    @rtype: L{DateTime}
    """
    if not rfc3339:
        return None
    else:
        datetime = DateTime.strptime(rfc3339, rfc3339_datetime_format)
        return datetime.replace(tzinfo=utc)

class JSON(Values):
    # Incident attribute keys
    incident_number   = ValueConstant("number")
    incident_created  = ValueConstant("timestamp")
    incident_priority = ValueConstant("priority")
    incident_state    = ValueConstant("state")
    incident_summary  = ValueConstant("summary")
    location_name     = ValueConstant("location_name")
    location_address  = ValueConstant("location_address")
    ranger_handles    = ValueConstant("ranger_handles")
    incident_types    = ValueConstant("incident_types")
    report_entries    = ValueConstant("report_entries")

    # State attribute values
    state_new         = ValueConstant("new")
    state_on_hold     = ValueConstant("on_hold")
    state_dispatched  = ValueConstant("dispatched")
    state_on_scene    = ValueConstant("on_scene")
    state_closed      = ValueConstant("closed")

    # Obsolete legacy state attribute keys
    _created          = ValueConstant("created")
    _dispatched       = ValueConstant("dispatched")
    _on_scene         = ValueConstant("on_scene")
    _closed           = ValueConstant("closed")

    # Ranger attribute keys
    ranger_handle = ValueConstant("handle")
    ranger_name   = ValueConstant("name")
    ranger_status = ValueConstant("status")

    # Report entry attribute keys
    entry_author      = ValueConstant("author")
    entry_text        = ValueConstant("text")
    entry_system      = ValueConstant("system_entry")
    entry_created     = ValueConstant("created")

    # Web page reference keys
    page_name = ValueConstant("name")
    page_url  = ValueConstant("url")

    @classmethod
    def describe(cls, value):
        """
        Describe a constant as a human-readable string.

        @param value: A JSON constant.
        @type constant: L{ValueConstant}

        @return: A string description of C{value}.
        @rtype: L{unicode}
        """
        value.name.replace("_", " ").decode("utf-8")

def incident_from_json(root, number, validate=True):
    """
    Create an incident from JSON data.

    @param root: JSON data representing an incident.
    @type root: L{dict}

    @param number: The number of the incident.
        If C{root} specifies an incident number that is different than
        C{number}, raise an L{InvalidDataError}.
    @type number: L{int}

    @param validate: If true, raise L{InvalidDataError} if the data does
        not validate as a fully-well-formed incident.
    @type validate: L{bool}

    @return: The de-serialized incident.
    @rtype: L{Incident}
    """
    if number is None:
        raise TypeError("Incident number may not be null")

    if not isinstance(root, dict):
        raise InvalidDataError("JSON incident must be a dict")

    for attribute in root:
        try:
            JSON.lookupByValue(attribute)
        except Exception:
            raise InvalidDataError("ARGH! Evil Death!")

    json_number = root.get(JSON.incident_number.value, None)

    if json_number is not None:
        if json_number != number:
            raise InvalidDataError(
                "Incident number may not be modified: {0!r} != {1!r}"
                .format(json_number, number)
            )

        root[JSON.incident_number.value] = number

    priority = root.get(JSON.incident_priority.value, None)

    summary = root.get(JSON.incident_summary.value, None)

    location_name = root.get(JSON.location_name.value, None)
    location_address = root.get(JSON.location_address.value, None)

    if location_name is None and location_address is None:
        location = None
    else:
        location = Location(name=location_name, address=location_address)

    ranger_handles = root.get(JSON.ranger_handles.value, None)
    if ranger_handles is None:
        rangers = None
    else:
        rangers = frozenset(
            Ranger(handle, None, None)
            for handle in ranger_handles
        )

    incident_types = root.get(JSON.incident_types.value, None)

    json_entries = root.get(JSON.report_entries.value, None)

    if json_entries is None:
        report_entries = None
    else:
        report_entries = [
            ReportEntry(
                author=entry.get(JSON.entry_author.value, None),
                text=entry.get(JSON.entry_text.value, None),
                created=rfc3339_as_datetime(
                    entry.get(JSON.entry_created.value, None)
                ),
                system_entry=entry.get(JSON.entry_system.value, False),
            )
            for entry in json_entries
        ]

    created = rfc3339_as_datetime(root.get(JSON.incident_created.value, None))

    json_state = root.get(JSON.incident_state.value, None)

    if json_state is None:
        if root.get(JSON._closed.value, None) is not None:
            state = IncidentState.closed

        elif root.get(JSON._on_scene.value, None) is not None:
            state = IncidentState.on_scene

        elif root.get(JSON._dispatched.value, None) is not None:
            state = IncidentState.dispatched

        elif root.get(JSON._created.value, None) is not None:
            state = IncidentState.new

        else:
            state = None

    else:
        state = IncidentState.lookupByName(json_state)

    incident = Incident(
        number=number,
        priority=priority,
        summary=summary,
        location=location,
        rangers=rangers,
        incident_types=incident_types,
        report_entries=report_entries,
        created=created,
        state=state,
    )

    if validate:
        incident.validate()

    return incident

def incident_as_json(incident):
    """
    Generate JSON data from an incident.

    @param incident: An incident to serialize.
    @type incident: L{Incident}

    @return: C{incident}, serialized as JSON data.
    @rtype: L{dict}
    """

    root = {}

    root[JSON.incident_number.value] = incident.number

    if incident.priority is not None:
        root[JSON.incident_priority.value] = incident.priority

    if incident.summary is not None:
        root[JSON.incident_summary.value] = incident.summary

    if incident.location is not None:
        root[JSON.location_name.value] = incident.location.name
        root[JSON.location_address.value] = incident.location.address

    if incident.rangers is not None:
        root[JSON.ranger_handles.value] = [
            ranger.handle for ranger in incident.rangers
        ]

    if incident.incident_types is not None:
        root[JSON.incident_types.value] = tuple(incident.incident_types)

    if incident.report_entries is not None:
        root[JSON.report_entries.value] = [
            {
                JSON.entry_author.value: entry.author,
                JSON.entry_text.value: entry.text,
                JSON.entry_created.value: datetime_as_rfc3339(entry.created),
                JSON.entry_system.value: entry.system_entry,
            }
            for entry in incident.report_entries
        ]

    if incident.created is not None:
        root[JSON.incident_created.value] = (
            datetime_as_rfc3339(incident.created)
        )

    if incident.state is not None:
        root[JSON.incident_state.value] = JSON.lookupByName(
            "state_{}".format(incident.state.name)
        ).value

    return root

def ranger_as_json(ranger):
    """
    Generate JSON data from a Ranger.

    @param ranger: A Ranger to serialize.
    @type ranger: L{Ranger}

    @return: C{ranger}, serialized as JSON data.
    @rtype: L{dict}
    """
    return {
        JSON.ranger_handle.value: ranger.handle,
        JSON.ranger_name.value: ranger.name,
        JSON.ranger_status.value: ranger.status,
    }

def location_as_json(location):
    """
    Generate JSON data from a location.

    @param location: A location to serialize.
    @type location: L{Location}

    @return: C{location}, serialized as JSON data.
    @rtype: L{dict}
    """
    return {
        "name": location.name,
        "address": location.address,
    }
<commit_msg>Note 2013 JSON schema<commit_after>##
# See the file COPYRIGHT for copyright information.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
##

from __future__ import absolute_import

"""
JSON bindings for IMS data.

2014 JSON incident schema replaces per-state time stamp attributes with a
created time stamp plus a state attribute:

    {
        "number": 101,                              // int >= 0
        "priority": 3,                              // int {1,3,5}
        "summary": "Diapers, please",               // one line
        "location_address": "8:15 & K",             // one line
        "location_name": "Camp Fishes",             // one line
        "ranger_handles": [
            "Santa Cruz"                            // handle in Clubhouse
        ],
        "incident_types": [
            "Law Enforcement"                       // from list in config
        ],
        "report_entries": [
            {
                "author": "Hot Yogi",               // handle in Clubhouse
                "created": "2014-08-30T21:12:50Z",  // RFC 3339, Zulu
                "system_entry": false,              // boolean
                "text": "Need diapers\nPronto"      // multi-line
            }
        ],
        "timestamp": "2014-08-30T21:38:11Z"         // RFC 3339, Zulu
        "state": "closed",                          // from JSON.state_*
    }

2013 JSON incident schema:

    {
        "number": 101,                              // int >= 0
        "priority": 3,                              // int {1,3,5}
        "summary": "Diapers, please",               // one line
        "location_address": "8:15 & K",             // one line
        "location_name": "Camp Fishes",             // one line
        "ranger_handles": [
            "Santa Cruz"                            // handle in Clubhouse
        ],
        "incident_types": [
            "Law Enforcement"                       // from list in config
        ],
        "report_entries": [
            {
                "author": "Hot Yogi",               // handle in Clubhouse
                "created": "2014-08-30T21:12:50Z",  // RFC 3339, Zulu
                "system_entry": false,              // boolean
                "text": "Need diapers\nPronto"      // multi-line
            }
        ],
        "created": "2014-08-30T21:38:11Z"           // RFC 3339, Zulu
        "dispatched": "2014-08-30T21:39:42Z"        // RFC 3339, Zulu
        "on_scene": "2014-08-30T21:45:53Z"          // RFC 3339, Zulu
        "closed": "2014-08-30T21:58:01Z"            // RFC 3339, Zulu
    }
"""

__all__ = [
    "json_from_file",
    "json_from_text",
    "json_as_text",

    "datetime_as_rfc3339",
    "rfc3339_as_datetime",

    "JSON",

    "incident_from_json",
    "incident_as_json",
]

from json import dumps, load as json_from_file, loads as json_from_text
from datetime import (
    datetime as DateTime,  # timedelta as TimeDelta, tzinfo as TZInfo
)

from twisted.python.constants import (
    Values, ValueConstant
)

from .tz import utc
from .data import (
    InvalidDataError, IncidentState, Incident, ReportEntry, Ranger, Location
)

rfc3339_datetime_format = "%Y-%m-%dT%H:%M:%SZ"

def json_as_text(obj):
    """
    Convert an object into JSON text.

    @param obj: An object that is serializable to JSON.
    @type obj: L{object}

    @return: JSON text.
    @rtype: L{unicode}
    """
    return dumps(obj, separators=(',', ':')).decode("UTF-8")

def datetime_as_rfc3339(datetime):
    """
    Convert a date-time object into an RFC 3339 formatted date-time string.

    @param datetime: A non-naive date-time object to convert.
    @type datetime: L{DateTime}

    @return: An RFC 3339 formatted date-time string corresponding to
        C{datetime} (converted to UTC).
    @rtype: L{str}
    """
    if not datetime:
        return None
    else:
        datetime = datetime.astimezone(utc)
        return datetime.strftime(rfc3339_datetime_format)

def rfc3339_as_datetime(rfc3339):
    """
    Convert an RFC 3339 formatted string to a date-time object.

    @param rfc3339: An RFC 3339 formatted string.
    @type rfc3339: L{str}

    @return: An date-time object (in UTC) corresponding to C{rfc3339}.
    @rtype: L{DateTime}
    """
    if not rfc3339:
        return None
    else:
        datetime = DateTime.strptime(rfc3339, rfc3339_datetime_format)
        return datetime.replace(tzinfo=utc)

class JSON(Values):
    # Incident attribute keys
    incident_number   = ValueConstant("number")
    incident_created  = ValueConstant("timestamp")
    incident_priority = ValueConstant("priority")
    incident_state    = ValueConstant("state")
    incident_summary  = ValueConstant("summary")
    location_name     = ValueConstant("location_name")
    location_address  = ValueConstant("location_address")
    ranger_handles    = ValueConstant("ranger_handles")
    incident_types    = ValueConstant("incident_types")
    report_entries    = ValueConstant("report_entries")

    # State attribute values
    state_new         = ValueConstant("new")
    state_on_hold     = ValueConstant("on_hold")
    state_dispatched  = ValueConstant("dispatched")
    state_on_scene    = ValueConstant("on_scene")
    state_closed      = ValueConstant("closed")

    # Obsolete legacy state attribute keys
    _created          = ValueConstant("created")
    _dispatched       = ValueConstant("dispatched")
    _on_scene         = ValueConstant("on_scene")
    _closed           = ValueConstant("closed")

    # Ranger attribute keys
    ranger_handle = ValueConstant("handle")
    ranger_name   = ValueConstant("name")
    ranger_status = ValueConstant("status")

    # Report entry attribute keys
    entry_author      = ValueConstant("author")
    entry_text        = ValueConstant("text")
    entry_system      = ValueConstant("system_entry")
    entry_created     = ValueConstant("created")

    # Web page reference keys
    page_name = ValueConstant("name")
    page_url  = ValueConstant("url")

    @classmethod
    def describe(cls, value):
        """
        Describe a constant as a human-readable string.

        @param value: A JSON constant.
        @type constant: L{ValueConstant}

        @return: A string description of C{value}.
        @rtype: L{unicode}
        """
        value.name.replace("_", " ").decode("utf-8")

def incident_from_json(root, number, validate=True):
    """
    Create an incident from JSON data.

    @param root: JSON data representing an incident.
    @type root: L{dict}

    @param number: The number of the incident.
        If C{root} specifies an incident number that is different than
        C{number}, raise an L{InvalidDataError}.
    @type number: L{int}

    @param validate: If true, raise L{InvalidDataError} if the data does
        not validate as a fully-well-formed incident.
    @type validate: L{bool}

    @return: The de-serialized incident.
    @rtype: L{Incident}
    """
    if number is None:
        raise TypeError("Incident number may not be null")

    if not isinstance(root, dict):
        raise InvalidDataError("JSON incident must be a dict")

    for attribute in root:
        try:
            JSON.lookupByValue(attribute)
        except Exception:
            raise InvalidDataError("ARGH! Evil Death!")

    json_number = root.get(JSON.incident_number.value, None)

    if json_number is not None:
        if json_number != number:
            raise InvalidDataError(
                "Incident number may not be modified: {0!r} != {1!r}"
                .format(json_number, number)
            )

        root[JSON.incident_number.value] = number

    priority = root.get(JSON.incident_priority.value, None)

    summary = root.get(JSON.incident_summary.value, None)

    location_name = root.get(JSON.location_name.value, None)
    location_address = root.get(JSON.location_address.value, None)

    if location_name is None and location_address is None:
        location = None
    else:
        location = Location(name=location_name, address=location_address)

    ranger_handles = root.get(JSON.ranger_handles.value, None)
    if ranger_handles is None:
        rangers = None
    else:
        rangers = frozenset(
            Ranger(handle, None, None)
            for handle in ranger_handles
        )

    incident_types = root.get(JSON.incident_types.value, None)

    json_entries = root.get(JSON.report_entries.value, None)

    if json_entries is None:
        report_entries = None
    else:
        report_entries = [
            ReportEntry(
                author=entry.get(JSON.entry_author.value, None),
                text=entry.get(JSON.entry_text.value, None),
                created=rfc3339_as_datetime(
                    entry.get(JSON.entry_created.value, None)
                ),
                system_entry=entry.get(JSON.entry_system.value, False),
            )
            for entry in json_entries
        ]

    created = rfc3339_as_datetime(root.get(JSON.incident_created.value, None))

    json_state = root.get(JSON.incident_state.value, None)

    if json_state is None:
        if root.get(JSON._closed.value, None) is not None:
            state = IncidentState.closed

        elif root.get(JSON._on_scene.value, None) is not None:
            state = IncidentState.on_scene

        elif root.get(JSON._dispatched.value, None) is not None:
            state = IncidentState.dispatched

        elif root.get(JSON._created.value, None) is not None:
            state = IncidentState.new

        else:
            state = None

    else:
        state = IncidentState.lookupByName(json_state)

    incident = Incident(
        number=number,
        priority=priority,
        summary=summary,
        location=location,
        rangers=rangers,
        incident_types=incident_types,
        report_entries=report_entries,
        created=created,
        state=state,
    )

    if validate:
        incident.validate()

    return incident

def incident_as_json(incident):
    """
    Generate JSON data from an incident.

    @param incident: An incident to serialize.
    @type incident: L{Incident}

    @return: C{incident}, serialized as JSON data.
    @rtype: L{dict}
    """

    root = {}

    root[JSON.incident_number.value] = incident.number

    if incident.priority is not None:
        root[JSON.incident_priority.value] = incident.priority

    if incident.summary is not None:
        root[JSON.incident_summary.value] = incident.summary

    if incident.location is not None:
        root[JSON.location_name.value] = incident.location.name
        root[JSON.location_address.value] = incident.location.address

    if incident.rangers is not None:
        root[JSON.ranger_handles.value] = [
            ranger.handle for ranger in incident.rangers
        ]

    if incident.incident_types is not None:
        root[JSON.incident_types.value] = tuple(incident.incident_types)

    if incident.report_entries is not None:
        root[JSON.report_entries.value] = [
            {
                JSON.entry_author.value: entry.author,
                JSON.entry_text.value: entry.text,
                JSON.entry_created.value: datetime_as_rfc3339(entry.created),
                JSON.entry_system.value: entry.system_entry,
            }
            for entry in incident.report_entries
        ]

    if incident.created is not None:
        root[JSON.incident_created.value] = (
            datetime_as_rfc3339(incident.created)
        )

    if incident.state is not None:
        root[JSON.incident_state.value] = JSON.lookupByName(
            "state_{}".format(incident.state.name)
        ).value

    return root

def ranger_as_json(ranger):
    """
    Generate JSON data from a Ranger.

    @param ranger: A Ranger to serialize.
    @type ranger: L{Ranger}

    @return: C{ranger}, serialized as JSON data.
    @rtype: L{dict}
    """
    return {
        JSON.ranger_handle.value: ranger.handle,
        JSON.ranger_name.value: ranger.name,
        JSON.ranger_status.value: ranger.status,
    }

def location_as_json(location):
    """
    Generate JSON data from a location.

    @param location: A location to serialize.
    @type location: L{Location}

    @return: C{location}, serialized as JSON data.
    @rtype: L{dict}
    """
    return {
        "name": location.name,
        "address": location.address,
    }
<|endoftext|>


<commit_before>__version__ = "0.7.1"
<commit_msg>Update version number.<commit_after>__version__ = "0.7.2"
<|endoftext|>


<commit_before>from analyzer import best
from config import Config
from plan import Plan
from glob import glob
from json import dump

def single(plan, config):
    distplan = best(plan, config)
    cost = distplan.cost(dest=config['CL1'])
    print 'Best cost:', cost
    distplan.printtree(dest=config['CL1'])
    return cost

def all_configs(plan, configs):
    results = {}
    for configfile, config in configs:
        print '\n' + (' BENCH %s ' % configfile).center(80, '-')
        results[configfile] = single(plan, config)
    return results

def all_plans(plans, configs):
    results = {}
    for planfile, plan in plans:
        print '\n' + (' PLAN %s ' % planfile).center(80, '=')
        plan.printtree()
        results[planfile] = all_configs(plan, configs)
    return results

plan_pattern = '../plans/*.xml'
config_pattern = '../configs/*.json'

plans = [(file, Plan.parse(file)) for file in glob(plan_pattern)]
configs = [(file, Config.parse(file)) for file in glob(config_pattern)]

with open('results.out', 'w') as outfile:
    dump(all_plans(plans, configs), outfile)
<commit_msg>add argparse to main.py<commit_after>#!/usr/bin/env python2

from argparse import ArgumentParser
from analyzer import best
from config import Config
from plan import Plan
from glob import glob
from json import dump

def single(plan, config):
    distplan = best(plan, config)
    cost = distplan.cost(dest=config['CL1'])
    print 'Best cost:', cost
    distplan.printtree(dest=config['CL1'])
    return cost

def all_configs(plan, configs):
    results = {}
    for configfile, config in configs:
        print '\n' + (' BENCH %s ' % configfile).center(80, '-')
        results[configfile] = single(plan, config)
    return results

def all_plans(plans, configs):
    results = {}
    for planfile, plan in plans:
        print '\n' + (' PLAN %s ' % planfile).center(80, '=')
        plan.printtree()
        results[planfile] = all_configs(plan, configs)
    return results

if __name__ == '__main__':
    parser = ArgumentParser(description='Optimize distributed Postgres queries',
        epilog="globs can be used like '../plans/*.xml' (single quotes!)")
    parser.add_argument('PLANS', help='query plan (or multiple using glob')
    parser.add_argument('CONFIGS', help='configuration (or multiple using glob')
    parser.add_argument('--out', default='results.out')
    args = parser.parse_args()

    #PLANS = '../plans/*.xml'
    #CONFIGS = '../configs/*.json'

    plans = [(file, Plan.parse(file)) for file in glob(args.PLANS)]
    configs = [(file, Config.parse(file)) for file in glob(args.CONFIGS)]

    with open(args.out, 'w') as outfile:
        dump(all_plans(plans, configs), outfile)
<|endoftext|>


<commit_before>"""
distribution.py
Author: Payton
Credit:

Assignment:

Write and submit a Python program (distribution.py) that computes and displays
the distribution of characters in a given sample of text.

Output of your program should look like this:

Please enter a string of text (the bigger the better): The rain in Spain stays mainly in the plain.
The distribution of characters in "The rain in Spain stays mainly in the plain." is:
iiiiii
nnnnnn
aaaaa
sss
ttt
ee
hh
ll
pp
yy
m
r

Notice about this example:

* The text: 'The rain ... plain' is provided by the user as input to your program.
* Uppercase characters are converted to lowercase
* Spaces and punctuation marks are ignored completely.
* Characters that are more common appear first in the list.
* Where the same number of characters occur, the lines are ordered alphabetically.
  For example, in the printout above, the letters e, h, l, p and y both occur twice
  in the text and they are listed in the output in alphabetical order.
* Letters that do not occur in the text are not listed in the output at all.
"""
def compare(a, b):
    return b > a

def bsort(seq, cmp):
    """
    bsort - simple sorting algorithm that uses any comparison function
    seq - a list to be sorted
    cmp - a function for comparing two elements of seq
    """
    sorted = False  # assume the seq is not sorted to start with
    while not sorted:
        sorted = True   # assume it's already sorted correctly
        for index, value in enumerate(seq): # for every element in seq
            if index > 0:                   # past the first..
                if not cmp(seq[index-1], value):  # if this element is out of order
                    sorted = False          # then the list is not sorted yet
                    seq[index-1], seq[index] = seq[index], seq[index-1] # and swap it

orig = str(input("Please enter a string of text (the bigger the better): "))
print('The distribution of character in "' + orig + '" is: ')
alph = "abcdefghijklmnopqrstuvwxyz"
results = []

for c in alph:
    r = orig.count(c)
    if not r == 0:
        t = (r*c)
        results.append(t)

bsort(results, compare)
print(results)<commit_msg>Updated from Brython Server: 2/22/2016 2:41:47 PM<commit_after>"""
distribution.py
Author: Payton
Credit:

Assignment:

Write and submit a Python program (distribution.py) that computes and displays
the distribution of characters in a given sample of text.

Output of your program should look like this:

Please enter a string of text (the bigger the better): The rain in Spain stays mainly in the plain.
The distribution of characters in "The rain in Spain stays mainly in the plain." is:
iiiiii
nnnnnn
aaaaa
sss
ttt
ee
hh
ll
pp
yy
m
r

Notice about this example:

* The text: 'The rain ... plain' is provided by the user as input to your program.
* Uppercase characters are converted to lowercase
* Spaces and punctuation marks are ignored completely.
* Characters that are more common appear first in the list.
* Where the same number of characters occur, the lines are ordered alphabetically.
  For example, in the printout above, the letters e, h, l, p and y both occur twice
  in the text and they are listed in the output in alphabetical order.
* Letters that do not occur in the text are not listed in the output at all.
"""
def compare(a, b):
    return b > a

orig = str(input("Please enter a string of text (the bigger the better): "))
print('The distribution of character in "' + orig + '" is: ')
alph = "abcdefghijklmnopqrstuvwxyz"
results = []

for c in alph:
    r = orig.count(c)
    if not r == 0:
        t = (r*c)
        results.append(t)

def bsort(seq, cmp):
    """
    bsort - simple sorting algorithm that uses any comparison function
    seq - a list to be sorted
    cmp - a function for comparing two elements of seq
    """
    sorted = False  # assume the seq is not sorted to start with
    while not sorted:
        sorted = True   # assume it's already sorted correctly
        for index, value in enumerate(seq): # for every element in seq
            if index > 0:                   # past the first..
                if not cmp(seq[index-1], value):  # if this element is out of order
                    sorted = False          # then the list is not sorted yet
                    seq[index-1], seq[index] = seq[index], seq[index-1] # and swap it

bsort(results, compare)
print(results)<|endoftext|>


<commit_before>"""
distribution.py
Author: Avery Wallis
Credit: Ethan, Payton, Doniel

Assignment:

Write and submit a Python program (distribution.py) that computes and displays
the distribution of characters in a given sample of text.

Output of your program should look like this:

Please enter a string of text (the bigger the better): The rain in Spain stays mainly in the plain.
The distribution of characters in "The rain in Spain stays mainly in the plain." is:
iiiiii
nnnnnn
aaaaa
sss
ttt
ee
hh
ll
pp
yy
m
r

Notice about this example:

* The text: 'The rain ... plain' is provided by the user as input to your program.
* Uppercase characters are converted to lowercase
* Spaces and punctuation marks are ignored completely.
* Characters that are more common appear first in the list.
* Where the same number of characters occur, the lines are ordered alphabetically.
  For example, in the printout above, the letters e, h, l, p and y both occur twice
  in the text and they are listed in the output in alphabetical order.
* Letters that do not occur in the text are not listed in the output at all.
"""
string= str(input("Please enter a string of text (the bigger the better): "))
string1=string.lower()
print('The distribution of characters in "'+string1+ '" is:')

alph='abcdefghijklmnopqrstuvwxyz'
result=[]
listnum=[]

for c in alph:
    r = string.count(c)
    if not r==0:
        t=(r*c)
        result.append(t)
        listnum.append(r)

lists=zip(listnum, result)
lists=sorted(lists, key=lambda listnum: listnum[0])   # sort by number
lists.sort(reverse=True)
print(list(lists))
l=len([x[1] for x in lists])
a=list([r[1] for r in lists])
for y in range(0,l-1):
    if len(a[y])==len(a[y+1]) or len(a[y])==len(a[y-1]):
        b=list([r[y] for r in lists])
        print(b)
    elif not len(a[y])==len(a[y+1]):
        print(a[y])

'''
https://docs.python.org/3/howto/sorting.html#sortinghowto
'''<commit_msg>Updated from Brython Server: 2/26/2016 2:43:53 PM<commit_after>"""
distribution.py
Author: Avery Wallis
Credit: Ethan, Payton, Doniel

Assignment:

Write and submit a Python program (distribution.py) that computes and displays
the distribution of characters in a given sample of text.

Output of your program should look like this:

Please enter a string of text (the bigger the better): The rain in Spain stays mainly in the plain.
The distribution of characters in "The rain in Spain stays mainly in the plain." is:
iiiiii
nnnnnn
aaaaa
sss
ttt
ee
hh
ll
pp
yy
m
r

Notice about this example:

* The text: 'The rain ... plain' is provided by the user as input to your program.
* Uppercase characters are converted to lowercase
* Spaces and punctuation marks are ignored completely.
* Characters that are more common appear first in the list.
* Where the same number of characters occur, the lines are ordered alphabetically.
  For example, in the printout above, the letters e, h, l, p and y both occur twice
  in the text and they are listed in the output in alphabetical order.
* Letters that do not occur in the text are not listed in the output at all.
"""
string= str(input("Please enter a string of text (the bigger the better): "))
string1=string.lower()
print('The distribution of characters in "'+string1+ '" is:')

alph='abcdefghijklmnopqrstuvwxyz'
result=[]
listnum=[]
thing=[]
for c in alph:
    r = string.count(c)
    if not r==0:
        t=(r*c)
        result.append(t)
        listnum.append(r)

lists=zip(listnum, result)
lists=sorted(lists, key=lambda listnum: listnum[0])   # sort by number
lists.sort(reverse=True)
print(list(lists))
l=len([x[1] for x in lists])
a=list([r[1] for r in lists])
for y in range(0,l-1):
    if len(a[y])==len(a[y+1]) or len(a[y])==len(a[y-1]):
        b=list(thing.append(a[y]))
        print(b)
    elif not len(a[y])==len(a[y+1]):
        print(a[y])

'''
https://docs.python.org/3/howto/sorting.html#sortinghowto
'''<|endoftext|>


<commit_before>"""
distribution.py
Author: Will Campbell
Credit: Dave Wilson, Ethan Adner

Assignment:

Write and submit a Python program (distribution.py) that computes and displays
the distribution of characters in a given sample of text.

Output of your program should look like this:

Please enter a string of text (the bigger the better): The rain in Spain stays mainly in the plain.
The distribution of characters in "The rain in Spain stays mainly in the plain." is:
iiiiii
nnnnnn
aaaaa
sss
ttt
ee
hh
ll
pp
yy
m
r

Notice about this example:

* The text: 'The rain ... plain' is provided by the user as input to your program.
* Uppercase characters are converted to lowercase
* Spaces and punctuation marks are ignored completely.
* Characters that are more common appear first in the list.
* Where the same number of characters occur, the lines are ordered alphabetically.
  For example, in the printout above, the letters e, h, l, p and y both occur twice
  in the text and they are listed in the output in alphabetical order.
* Letters that do not occur in the text are not listed in the output at all.
"""
string = input("Please enter a string of text (the bigger the better): ").lower()
list = list(string)
alpha=["a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z"]
freq=[]
for x in alpha:
    freq.append(0)
for x in list:
    if x in alpha:
       freq[alpha.index(x)]=freq[alpha.index(x)]+1

a=0

<commit_msg>Updated from Brython Server: 3/22/2016 2:40:24 PM<commit_after>"""
distribution.py
Author: Will Campbell
Credit: Dave Wilson, Ethan Adner

Assignment:

Write and submit a Python program (distribution.py) that computes and displays
the distribution of characters in a given sample of text.

Output of your program should look like this:

Please enter a string of text (the bigger the better): The rain in Spain stays mainly in the plain.
The distribution of characters in "The rain in Spain stays mainly in the plain." is:
iiiiii
nnnnnn
aaaaa
sss
ttt
ee
hh
ll
pp
yy
m
r

Notice about this example:

* The text: 'The rain ... plain' is provided by the user as input to your program.
* Uppercase characters are converted to lowercase
* Spaces and punctuation marks are ignored completely.
* Characters that are more common appear first in the list.
* Where the same number of characters occur, the lines are ordered alphabetically.
  For example, in the printout above, the letters e, h, l, p and y both occur twice
  in the text and they are listed in the output in alphabetical order.
* Letters that do not occur in the text are not listed in the output at all.
"""
string = input("Please enter a string of text (the bigger the better): ").lower()
list = list(string)
alpha=["a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z"]
freq=[]
for x in alpha:
    freq.append(0)
for x in list:
    if x in alpha:
       freq[alpha.index(x)]=freq[alpha.index(x)]+1

print(freq)
a=0

<|endoftext|>


<commit_before>import sys
from django.conf import settings
from django.conf.urls import patterns, include, url
from django.views.generic.base import TemplateView
from dj_phab import views

urlpatterns = patterns('',
    url(r'^$', views.IndexView.as_view(), name='djp-index'),
    url(r'^basic/$', views.DataView.as_view(), name='djp-basic'),
    url(r'^basic/(?P<granularity>year|month|week|day)$', views.DataView.as_view(), name='djp-basic_granular'),
)

if 'test' in sys.argv or getattr(settings, 'DEBUG', False):
    urlpatterns += patterns('',
        url(r'^smoke/$', TemplateView.as_view(template_name='dj_phab/smoke.html'), name='djp-smoke'),
    )
<commit_msg>typo: URL missing trailing slash<commit_after>import sys
from django.conf import settings
from django.conf.urls import patterns, include, url
from django.views.generic.base import TemplateView
from dj_phab import views

urlpatterns = patterns('',
    url(r'^$', views.IndexView.as_view(), name='djp-index'),
    url(r'^basic/$', views.DataView.as_view(), name='djp-basic'),
    url(r'^basic/(?P<granularity>year|month|week|day)/$', views.DataView.as_view(), name='djp-basic_granular'),
)

if 'test' in sys.argv or getattr(settings, 'DEBUG', False):
    urlpatterns += patterns('',
        url(r'^smoke/$', TemplateView.as_view(template_name='dj_phab/smoke.html'), name='djp-smoke'),
    )
<|endoftext|>


<commit_before>from django.contrib.auth import get_user_model
from django.contrib.auth.tokens import default_token_generator
from django.urls.exceptions import NoReverseMatch
from django.utils.timezone import now
from rest_framework import (
    generics,
    permissions,
    response,
    status, views,
    viewsets,
)
from rest_framework.decorators import list_route
from rest_framework.response import Response
from rest_framework.reverse import reverse

from djoser import utils, signals
from djoser.compat import get_user_email, get_user_email_field_name
from djoser.conf import settings
from djoser.utils import ActionViewMixin

User = get_user_model()

class RootView(views.APIView):
    """
    Root endpoint - use one of sub endpoints.
    """
    permission_classes = [permissions.AllowAny]

    def _get_url_names(self, urllist):
        names = []
        for entry in urllist:
            if hasattr(entry, 'url_patterns'):
                names.extend(self._get_url_names(entry.url_patterns))
            else:
                names.append(entry.name)
        return names

    def aggregate_djoser_urlpattern_names(self):
        from djoser.urls import base, authtoken
        urlpattern_names = self._get_url_names(base.urlpatterns)
        urlpattern_names += self._get_url_names(authtoken.urlpatterns)
        urlpattern_names += self._get_jwt_urlpatterns()

        return urlpattern_names

    def get_urls_map(self, request, urlpattern_names, fmt):
        urls_map = {}
        for urlpattern_name in urlpattern_names:
            try:
                url = reverse(urlpattern_name, request=request, format=fmt)
            except NoReverseMatch:
                url = ''
            urls_map[urlpattern_name] = url
        return urls_map

    def get(self, request, fmt=None):
        urlpattern_names = self.aggregate_djoser_urlpattern_names()
        urls_map = self.get_urls_map(request, urlpattern_names, fmt)
        return Response(urls_map)

    def _get_jwt_urlpatterns(self):
        try:
            from djoser.urls import jwt
            return self._get_url_names(jwt.urlpatterns)
        except ImportError:
            return []

class UserCreateMixin:
    def perform_create(self, serializer):
        user = serializer.save()
        signals.user_registered.send(
            sender=self.__class__, user=user, request=self.request
        )

        context = {'user': user}
        to = [get_user_email(user)]
        if settings.SEND_ACTIVATION_EMAIL:
            settings.EMAIL.activation(self.request, context).send(to)
        elif settings.SEND_CONFIRMATION_EMAIL:
            settings.EMAIL.confirmation(self.request, context).send(to)

class UserCreateView(UserCreateMixin, generics.CreateAPIView):
    """
    Use this endpoint to register new user.
    """
    serializer_class = settings.SERIALIZERS.user_create
    permission_classes = settings.PERMISSIONS.user_create

class ResendActivationView(ActionViewMixin, generics.GenericAPIView):
    """
    Use this endpoint to resend user activation email.
    """
    serializer_class = settings.SERIALIZERS.password_reset
    permission_classes = [permissions.AllowAny]

    _users = None

    def _action(self, serializer):
        if not settings.SEND_ACTIVATION_EMAIL:
            return response.Response(status=status.HTTP_400_BAD_REQUEST)
        for user in self.get_users(serializer.data['email']):
            self.send_activation_email(user)
        return response.Response(status=status.HTTP_204_NO_CONTENT)

    def get_users(self, email):
        if self._users is None:
            email_field_name = get_user_email_field_name(User)
            users = User._default_manager.filter(**{
                email_field_name + '__iexact': email
            })
            self._users = [
                u for u in users if not u.is_active and u.has_usable_password()
            ]
        return self._users

    def send_activation_email(self, user):
        context = {'user': user}
        to = [get_user_email(user)]
        settings.EMAIL.activation(self.request, context).send(to)

class UserDeleteView(generics.CreateAPIView):
    """
    Use this endpoint to remove actually authenticated user
    """
    serializer_class = settings.SERIALIZERS.user_delete
    permission_classes = settings.PERMISSIONS.user_delete

    def get_object(self):
        return self.request.user

    def post(self, request, *args, **kwargs):
        instance = self.get_object()
        serializer = self.get_serializer(instance, data=request.data)
        serializer.is_valid(raise_exception=True)

        utils.logout_user(self.request)
        instance.delete()

        return Response(status=status.HTTP_204_NO_CONTENT)

class TokenCreateView(utils.ActionViewMixin, generics.GenericAPIView):
    """
    Use this endpoint to obtain user authentication token.
    """
    serializer_class = settings.SERIALIZERS.token_create
    permission_classes = settings.PERMISSIONS.token_create

    def _action(self, serializer):
        token = utils.login_user(self.request, serializer.user)
        token_serializer_class = settings.SERIALIZERS.token
        return Response(
            data=token_serializer_class(token).data,
            status=status.HTTP_200_OK,
        )

class TokenDestroyView(views.APIView):
    """
    Use this endpoint to logout user (remove user authentication token).
    """
    permission_classes = settings.PERMISSIONS.token_destroy

    def post(self, request):
        utils.logout_user(request)
        return Response(status=status.HTTP_204_NO_CONTENT)

class PasswordResetView(utils.ActionViewMixin, generics.GenericAPIView):
    """
    Use this endpoint to send email to user with password reset link.
    """
    serializer_class = settings.SERIALIZERS.password_reset
    permission_classes = settings.PERMISSIONS.password_reset

    _users = None

    def _action(self, serializer):
        for user in self.get_users(serializer.data['email']):
            self.send_password_reset_email(user)
        return Response(status=status.HTTP_204_NO_CONTENT)

    def get_users(self, email):
        if self._users is None:
            email_field_name = get_user_email_field_name(User)
            users = User._default_manager.filter(**{
                email_field_name + '__iexact': email
            })
            self._users = [
                u for u in users if u.is_active and u.has_usable_password()
            ]
        return self._users

    def send_password_reset_email(self, user):
        context = {'user': user}
        to = [get_user_email(user)]
        settings.EMAIL.password_reset(self.request, context).send(to)

class SetPasswordView(utils.ActionViewMixin, generics.GenericAPIView):
    """
    Use this endpoint to change user password.
    """
    permission_classes = settings.PERMISSIONS.set_password

    def get_serializer_class(self):
        if settings.SET_PASSWORD_RETYPE:
            return settings.SERIALIZERS.set_password_retype
        return settings.SERIALIZERS.set_password

    def _action(self, serializer):
        self.request.user.set_password(serializer.data['new_password'])
        self.request.user.save()

        if settings.LOGOUT_ON_PASSWORD_CHANGE:
            utils.logout_user(self.request)

        return Response(status=status.HTTP_204_NO_CONTENT)

class PasswordResetConfirmView(utils.ActionViewMixin, generics.GenericAPIView):
    """
    Use this endpoint to finish reset password process.
    """
    permission_classes = settings.PERMISSIONS.password_reset_confirm
    token_generator = default_token_generator

    def get_serializer_class(self):
        if settings.PASSWORD_RESET_CONFIRM_RETYPE:
            return settings.SERIALIZERS.password_reset_confirm_retype
        return settings.SERIALIZERS.password_reset_confirm

    def _action(self, serializer):
        serializer.user.set_password(serializer.data['new_password'])
        if hasattr(serializer.user, 'last_login'):
            serializer.user.last_login = now()
        serializer.user.save()
        return Response(status=status.HTTP_204_NO_CONTENT)

class ActivationView(utils.ActionViewMixin, generics.GenericAPIView):
    """
    Use this endpoint to activate user account.
    """
    serializer_class = settings.SERIALIZERS.activation
    permission_classes = settings.PERMISSIONS.activation
    token_generator = default_token_generator

    def _action(self, serializer):
        user = serializer.user
        user.is_active = True
        user.save()

        signals.user_activated.send(
            sender=self.__class__, user=user, request=self.request
        )

        if settings.SEND_CONFIRMATION_EMAIL:
            context = {'user': user}
            to = [get_user_email(user)]
            settings.EMAIL.confirmation(self.request, context).send(to)

        return Response(status=status.HTTP_204_NO_CONTENT)

class SetUsernameView(utils.ActionViewMixin, generics.GenericAPIView):
    """
    Use this endpoint to change user username.
    """
    permission_classes = settings.PERMISSIONS.set_username

    def get_serializer_class(self):
        if settings.SET_USERNAME_RETYPE:
            return settings.SERIALIZERS.set_username_retype
        return settings.SERIALIZERS.set_username

    def _action(self, serializer):
        user = self.request.user
        new_username = serializer.data['new_' + User.USERNAME_FIELD]

        setattr(user, User.USERNAME_FIELD, new_username)
        if settings.SEND_ACTIVATION_EMAIL:
            user.is_active = False
            context = {'user': user}
            to = [get_user_email(user)]
            settings.EMAIL.activation(self.request, context).send(to)
        user.save()

        return Response(status=status.HTTP_204_NO_CONTENT)

class UserUpdateMixin(object):
    def perform_update(self, serializer):
        super(UserUpdateMixin, self).perform_update(serializer)
        user = serializer.instance
        if settings.SEND_ACTIVATION_EMAIL and not user.is_active:
            context = {'user': user}
            to = [get_user_email(user)]
            settings.EMAIL.activation(self.request, context).send(to)

class UserView(UserUpdateMixin,
               generics.RetrieveUpdateAPIView):
    """
    Use this endpoint to retrieve/update user.
    """
    queryset = User.objects.all()
    serializer_class = settings.SERIALIZERS.user
    permission_classes = settings.PERMISSIONS.user

    def get_object(self, *args, **kwargs):
        return self.request.user

class UserViewSet(UserCreateMixin,
                  UserUpdateMixin,
                  viewsets.ModelViewSet):
    serializer_class = settings.SERIALIZERS.user
    queryset = User.objects.all()
    permission_classes = settings.PERMISSIONS.user
    token_generator = default_token_generator

    def get_queryset(self):
        qs = super().get_queryset()
        user = self.request.user
        if not user.is_staff:
            qs = qs.filter(pk=user.pk)
        return qs

    def get_permissions(self):
        if self.action == 'create':
            self.permission_classes = settings.PERMISSIONS.user_create
        elif self.action == 'confirm':
            self.permission_classes = settings.PERMISSIONS.activation
        elif self.action == 'list':
            self.permission_classes = settings.PERMISSIONS.user_list
        return super(UserViewSet, self).get_permissions()

    def get_serializer_class(self):
        if self.action == 'create':
            return settings.SERIALIZERS.user_create

        elif self.action == 'remove' or (
                self.action == 'me' and self.request and
                self.request.method == 'DELETE'
        ):
            return settings.SERIALIZERS.user_delete

        elif self.action == 'confirm':
            return settings.SERIALIZERS.activation

        elif self.action == 'change_username':
            if settings.SET_USERNAME_RETYPE:
                return settings.SERIALIZERS.set_username_retype

            return settings.SERIALIZERS.set_username

        elif self.action == 'me':
            # Use the current user serializer on 'me' endpoints
            return settings.SERIALIZERS.current_user

        return self.serializer_class

    def get_instance(self):
        return self.request.user

    def perform_destroy(self, instance):
        utils.logout_user(self.request)
        super(UserViewSet, self).perform_destroy(instance)

    def destroy(self, request, *args, **kwargs):
        instance = self.get_object()
        serializer = self.get_serializer(instance, data=request.data)
        serializer.is_valid(raise_exception=True)

        self.perform_destroy(instance)
        return Response(status=status.HTTP_204_NO_CONTENT)

    @list_route(['get', 'put', 'patch', 'delete'])
    def me(self, request, *args, **kwargs):
        self.get_object = self.get_instance
        if request.method == 'GET':
            return self.retrieve(request, *args, **kwargs)
        elif request.method == 'PUT':
            return self.update(request, *args, **kwargs)
        elif request.method == 'PATCH':
            return self.partial_update(request, *args, **kwargs)
        elif request.method == 'DELETE':
            return self.destroy(request, *args, **kwargs)

    @list_route(['post'])
    def confirm(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        user = serializer.user
        user.is_active = True
        user.save()

        signals.user_activated.send(
            sender=self.__class__, user=user, request=self.request
        )

        if settings.SEND_CONFIRMATION_EMAIL:
            context = {'user': user}
            to = [get_user_email(user)]
            settings.EMAIL.confirmation(self.request, context).send(to)

        return Response(status=status.HTTP_204_NO_CONTENT)

    @list_route(['post'])
    def change_username(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        user = self.request.user
        new_username = serializer.data['new_' + User.USERNAME_FIELD]

        setattr(user, User.USERNAME_FIELD, new_username)
        if settings.SEND_ACTIVATION_EMAIL:
            user.is_active = False
            context = {'user': user}
            to = [get_user_email(user)]
            settings.EMAIL.activation(self.request, context).send(to)
        user.save()

        return Response(status=status.HTTP_204_NO_CONTENT)
<commit_msg>Fix regression introduced in 5b92a1fbbd<commit_after>from django.contrib.auth import get_user_model
from django.contrib.auth.tokens import default_token_generator
from django.urls.exceptions import NoReverseMatch
from django.utils.timezone import now
from rest_framework import (
    generics,
    permissions,
    response,
    status, views,
    viewsets,
)
from rest_framework.decorators import list_route
from rest_framework.response import Response
from rest_framework.reverse import reverse

from djoser import utils, signals
from djoser.compat import get_user_email, get_user_email_field_name
from djoser.conf import settings
from djoser.utils import ActionViewMixin

User = get_user_model()

class RootView(views.APIView):
    """
    Root endpoint - use one of sub endpoints.
    """
    permission_classes = [permissions.AllowAny]

    def _get_url_names(self, urllist):
        names = []
        for entry in urllist:
            if hasattr(entry, 'url_patterns'):
                names.extend(self._get_url_names(entry.url_patterns))
            else:
                names.append(entry.name)
        return names

    def aggregate_djoser_urlpattern_names(self):
        from djoser.urls import base, authtoken
        urlpattern_names = self._get_url_names(base.urlpatterns)
        urlpattern_names += self._get_url_names(authtoken.urlpatterns)
        urlpattern_names += self._get_jwt_urlpatterns()

        return urlpattern_names

    def get_urls_map(self, request, urlpattern_names, fmt):
        urls_map = {}
        for urlpattern_name in urlpattern_names:
            try:
                url = reverse(urlpattern_name, request=request, format=fmt)
            except NoReverseMatch:
                url = ''
            urls_map[urlpattern_name] = url
        return urls_map

    def get(self, request, fmt=None):
        urlpattern_names = self.aggregate_djoser_urlpattern_names()
        urls_map = self.get_urls_map(request, urlpattern_names, fmt)
        return Response(urls_map)

    def _get_jwt_urlpatterns(self):
        try:
            from djoser.urls import jwt
            return self._get_url_names(jwt.urlpatterns)
        except ImportError:
            return []

class UserCreateMixin:
    def perform_create(self, serializer):
        user = serializer.save()
        signals.user_registered.send(
            sender=self.__class__, user=user, request=self.request
        )

        context = {'user': user}
        to = [get_user_email(user)]
        if settings.SEND_ACTIVATION_EMAIL:
            settings.EMAIL.activation(self.request, context).send(to)
        elif settings.SEND_CONFIRMATION_EMAIL:
            settings.EMAIL.confirmation(self.request, context).send(to)

class UserCreateView(UserCreateMixin, generics.CreateAPIView):
    """
    Use this endpoint to register new user.
    """
    serializer_class = settings.SERIALIZERS.user_create
    permission_classes = settings.PERMISSIONS.user_create

class ResendActivationView(ActionViewMixin, generics.GenericAPIView):
    """
    Use this endpoint to resend user activation email.
    """
    serializer_class = settings.SERIALIZERS.password_reset
    permission_classes = [permissions.AllowAny]

    _users = None

    def _action(self, serializer):
        if not settings.SEND_ACTIVATION_EMAIL:
            return response.Response(status=status.HTTP_400_BAD_REQUEST)
        for user in self.get_users(serializer.data['email']):
            self.send_activation_email(user)
        return response.Response(status=status.HTTP_204_NO_CONTENT)

    def get_users(self, email):
        if self._users is None:
            email_field_name = get_user_email_field_name(User)
            users = User._default_manager.filter(**{
                email_field_name + '__iexact': email
            })
            self._users = [
                u for u in users if not u.is_active and u.has_usable_password()
            ]
        return self._users

    def send_activation_email(self, user):
        context = {'user': user}
        to = [get_user_email(user)]
        settings.EMAIL.activation(self.request, context).send(to)

class UserDeleteView(generics.CreateAPIView):
    """
    Use this endpoint to remove actually authenticated user
    """
    serializer_class = settings.SERIALIZERS.user_delete
    permission_classes = settings.PERMISSIONS.user_delete

    def get_object(self):
        return self.request.user

    def post(self, request, *args, **kwargs):
        instance = self.get_object()
        serializer = self.get_serializer(instance, data=request.data)
        serializer.is_valid(raise_exception=True)

        utils.logout_user(self.request)
        instance.delete()

        return Response(status=status.HTTP_204_NO_CONTENT)

class TokenCreateView(utils.ActionViewMixin, generics.GenericAPIView):
    """
    Use this endpoint to obtain user authentication token.
    """
    serializer_class = settings.SERIALIZERS.token_create
    permission_classes = settings.PERMISSIONS.token_create

    def _action(self, serializer):
        token = utils.login_user(self.request, serializer.user)
        token_serializer_class = settings.SERIALIZERS.token
        return Response(
            data=token_serializer_class(token).data,
            status=status.HTTP_200_OK,
        )

class TokenDestroyView(views.APIView):
    """
    Use this endpoint to logout user (remove user authentication token).
    """
    permission_classes = settings.PERMISSIONS.token_destroy

    def post(self, request):
        utils.logout_user(request)
        return Response(status=status.HTTP_204_NO_CONTENT)

class PasswordResetView(utils.ActionViewMixin, generics.GenericAPIView):
    """
    Use this endpoint to send email to user with password reset link.
    """
    serializer_class = settings.SERIALIZERS.password_reset
    permission_classes = settings.PERMISSIONS.password_reset

    _users = None

    def _action(self, serializer):
        for user in self.get_users(serializer.data['email']):
            self.send_password_reset_email(user)
        return Response(status=status.HTTP_204_NO_CONTENT)

    def get_users(self, email):
        if self._users is None:
            email_field_name = get_user_email_field_name(User)
            users = User._default_manager.filter(**{
                email_field_name + '__iexact': email
            })
            self._users = [
                u for u in users if u.is_active and u.has_usable_password()
            ]
        return self._users

    def send_password_reset_email(self, user):
        context = {'user': user}
        to = [get_user_email(user)]
        settings.EMAIL.password_reset(self.request, context).send(to)

class SetPasswordView(utils.ActionViewMixin, generics.GenericAPIView):
    """
    Use this endpoint to change user password.
    """
    permission_classes = settings.PERMISSIONS.set_password

    def get_serializer_class(self):
        if settings.SET_PASSWORD_RETYPE:
            return settings.SERIALIZERS.set_password_retype
        return settings.SERIALIZERS.set_password

    def _action(self, serializer):
        self.request.user.set_password(serializer.data['new_password'])
        self.request.user.save()

        if settings.LOGOUT_ON_PASSWORD_CHANGE:
            utils.logout_user(self.request)

        return Response(status=status.HTTP_204_NO_CONTENT)

class PasswordResetConfirmView(utils.ActionViewMixin, generics.GenericAPIView):
    """
    Use this endpoint to finish reset password process.
    """
    permission_classes = settings.PERMISSIONS.password_reset_confirm
    token_generator = default_token_generator

    def get_serializer_class(self):
        if settings.PASSWORD_RESET_CONFIRM_RETYPE:
            return settings.SERIALIZERS.password_reset_confirm_retype
        return settings.SERIALIZERS.password_reset_confirm

    def _action(self, serializer):
        serializer.user.set_password(serializer.data['new_password'])
        if hasattr(serializer.user, 'last_login'):
            serializer.user.last_login = now()
        serializer.user.save()
        return Response(status=status.HTTP_204_NO_CONTENT)

class ActivationView(utils.ActionViewMixin, generics.GenericAPIView):
    """
    Use this endpoint to activate user account.
    """
    serializer_class = settings.SERIALIZERS.activation
    permission_classes = settings.PERMISSIONS.activation
    token_generator = default_token_generator

    def _action(self, serializer):
        user = serializer.user
        user.is_active = True
        user.save()

        signals.user_activated.send(
            sender=self.__class__, user=user, request=self.request
        )

        if settings.SEND_CONFIRMATION_EMAIL:
            context = {'user': user}
            to = [get_user_email(user)]
            settings.EMAIL.confirmation(self.request, context).send(to)

        return Response(status=status.HTTP_204_NO_CONTENT)

class SetUsernameView(utils.ActionViewMixin, generics.GenericAPIView):
    """
    Use this endpoint to change user username.
    """
    permission_classes = settings.PERMISSIONS.set_username

    def get_serializer_class(self):
        if settings.SET_USERNAME_RETYPE:
            return settings.SERIALIZERS.set_username_retype
        return settings.SERIALIZERS.set_username

    def _action(self, serializer):
        user = self.request.user
        new_username = serializer.data['new_' + User.USERNAME_FIELD]

        setattr(user, User.USERNAME_FIELD, new_username)
        if settings.SEND_ACTIVATION_EMAIL:
            user.is_active = False
            context = {'user': user}
            to = [get_user_email(user)]
            settings.EMAIL.activation(self.request, context).send(to)
        user.save()

        return Response(status=status.HTTP_204_NO_CONTENT)

class UserUpdateMixin(object):
    def perform_update(self, serializer):
        super(UserUpdateMixin, self).perform_update(serializer)
        user = serializer.instance
        if settings.SEND_ACTIVATION_EMAIL and not user.is_active:
            context = {'user': user}
            to = [get_user_email(user)]
            settings.EMAIL.activation(self.request, context).send(to)

class UserView(UserUpdateMixin,
               generics.RetrieveUpdateAPIView):
    """
    Use this endpoint to retrieve/update user.
    """
    queryset = User.objects.all()
    serializer_class = settings.SERIALIZERS.user
    permission_classes = settings.PERMISSIONS.user

    def get_object(self, *args, **kwargs):
        return self.request.user

class UserViewSet(UserCreateMixin,
                  UserUpdateMixin,
                  viewsets.ModelViewSet):
    serializer_class = settings.SERIALIZERS.user
    queryset = User.objects.all()
    permission_classes = settings.PERMISSIONS.user
    token_generator = default_token_generator

    def get_queryset(self):
        qs = super(UserViewSet, self).get_queryset()
        user = self.request.user
        if not (user.is_staff or user.is_superuser):
            qs = qs.filter(pk=user.pk)
        return qs

    def get_permissions(self):
        if self.action == 'create':
            self.permission_classes = settings.PERMISSIONS.user_create
        elif self.action == 'confirm':
            self.permission_classes = settings.PERMISSIONS.activation
        elif self.action == 'list':
            self.permission_classes = settings.PERMISSIONS.user_list
        return super(UserViewSet, self).get_permissions()

    def get_serializer_class(self):
        if self.action == 'create':
            return settings.SERIALIZERS.user_create

        elif self.action == 'remove' or (
                self.action == 'me' and self.request and
                self.request.method == 'DELETE'
        ):
            return settings.SERIALIZERS.user_delete

        elif self.action == 'confirm':
            return settings.SERIALIZERS.activation

        elif self.action == 'change_username':
            if settings.SET_USERNAME_RETYPE:
                return settings.SERIALIZERS.set_username_retype

            return settings.SERIALIZERS.set_username

        elif self.action == 'me':
            # Use the current user serializer on 'me' endpoints
            return settings.SERIALIZERS.current_user

        return self.serializer_class

    def get_instance(self):
        return self.request.user

    def perform_destroy(self, instance):
        utils.logout_user(self.request)
        super(UserViewSet, self).perform_destroy(instance)

    def destroy(self, request, *args, **kwargs):
        instance = self.get_object()
        serializer = self.get_serializer(instance, data=request.data)
        serializer.is_valid(raise_exception=True)

        self.perform_destroy(instance)
        return Response(status=status.HTTP_204_NO_CONTENT)

    @list_route(['get', 'put', 'patch', 'delete'])
    def me(self, request, *args, **kwargs):
        self.get_object = self.get_instance
        if request.method == 'GET':
            return self.retrieve(request, *args, **kwargs)
        elif request.method == 'PUT':
            return self.update(request, *args, **kwargs)
        elif request.method == 'PATCH':
            return self.partial_update(request, *args, **kwargs)
        elif request.method == 'DELETE':
            return self.destroy(request, *args, **kwargs)

    @list_route(['post'])
    def confirm(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        user = serializer.user
        user.is_active = True
        user.save()

        signals.user_activated.send(
            sender=self.__class__, user=user, request=self.request
        )

        if settings.SEND_CONFIRMATION_EMAIL:
            context = {'user': user}
            to = [get_user_email(user)]
            settings.EMAIL.confirmation(self.request, context).send(to)

        return Response(status=status.HTTP_204_NO_CONTENT)

    @list_route(['post'])
    def change_username(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        user = self.request.user
        new_username = serializer.data['new_' + User.USERNAME_FIELD]

        setattr(user, User.USERNAME_FIELD, new_username)
        if settings.SEND_ACTIVATION_EMAIL:
            user.is_active = False
            context = {'user': user}
            to = [get_user_email(user)]
            settings.EMAIL.activation(self.request, context).send(to)
        user.save()

        return Response(status=status.HTTP_204_NO_CONTENT)
<|endoftext|>