<commit_before># The MIT License
#
# Copyright 2013 Sony Mobile Communications. All rights reserved.
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.

""" Interface to the Gerrit REST API. """

import json
import logging
import requests

GERRIT_MAGIC_JSON_PREFIX = ")]}\'\n"
GERRIT_AUTH_SUFFIX = "/a"

def _decode_response(response):
    """ Strip off Gerrit's magic prefix and decode a response.

    :returns:
        Decoded JSON content as a dict, or raw text if content could not be
        decoded as JSON.

    :raises:
        requests.HTTPError if the response contains an HTTP error status code.

    """
    content = response.content.strip()
    if response.encoding:
        content = content.decode(response.encoding)
    response.raise_for_status()
    content_type = response.headers.get('content-type', '')
    if content_type.split(';')[0] != 'application/json':
        return content
    if content.startswith(GERRIT_MAGIC_JSON_PREFIX):
        content = content[len(GERRIT_MAGIC_JSON_PREFIX):]
    try:
        return json.loads(content)
    except ValueError:
        logging.error('Invalid json content: %s' % content)
        raise

def _merge_dict(result, overrides):
    """ Deep-merge dictionaries.

    :arg dict result: The resulting dictionary
    :arg dict overrides: Dictionay being merged into the result

    :returns:
        The resulting dictionary

    """
    for key in overrides:
        if (
            key in result and
            isinstance(result[key], dict) and
            isinstance(overrides[key], dict)
        ):
            _merge_dict(result[key], overrides[key])
        else:
            result[key] = overrides[key]
    return result

class GerritRestAPI(object):

    """ Interface to the Gerrit REST API.

    :arg str url: The full URL to the server, including the `http(s)://` prefix.
        If `auth` is given, `url` will be automatically adjusted to include
        Gerrit's authentication suffix.
    :arg auth: (optional) Authentication handler.  Must be derived from
        `requests.auth.AuthBase`.
    :arg boolean verify: (optional) Set to False to disable verification of
        SSL certificates.

    """

    def __init__(self, url, auth=None, verify=True):
        headers = {'Accept': 'application/json',
                   'Accept-Encoding': 'gzip'}
        self.kwargs = {'auth': auth,
                       'verify': verify,
                       'headers': headers}
        self.url = url.rstrip('/')
        self.session = requests.session()

        if auth:
            if not isinstance(auth, requests.auth.AuthBase):
                raise ValueError('Invalid auth type; must be derived '
                                 'from requests.auth.AuthBase')

            if not self.url.endswith(GERRIT_AUTH_SUFFIX):
                self.url += GERRIT_AUTH_SUFFIX
        else:
            if self.url.endswith(GERRIT_AUTH_SUFFIX):
                self.url = self.url[: - len(GERRIT_AUTH_SUFFIX)]

        if not self.url.endswith('/'):
            self.url += '/'

    def make_url(self, endpoint):
        """ Make the full url for the endpoint.

        :arg str endpoint: The endpoint.

        :returns:
            The full url.

        """
        endpoint = endpoint.lstrip('/')
        return self.url + endpoint

    def get(self, endpoint, return_response=False, **kwargs):
        """ Send HTTP GET to the endpoint.

        :arg str endpoint: The endpoint to send to.
        :arg bool return_response: If true will also return the response

        :returns:
            JSON decoded result.

        :raises:
            requests.RequestException on timeout or connection error.

        """
        kwargs.update(self.kwargs.copy())
        response = self.session.get(self.make_url(endpoint), **kwargs)

        decoded_response = _decode_response(response)

        if return_response:
            return decoded_response, response
        return decoded_response

    def put(self, endpoint, return_response=False, **kwargs):
        """ Send HTTP PUT to the endpoint.

        :arg str endpoint: The endpoint to send to.

        :returns:
            JSON decoded result.

        :raises:
            requests.RequestException on timeout or connection error.

        """
        args = {}
        if "data" in kwargs or "json" in kwargs:
            _merge_dict(
                args, {
                    "headers": {
                        "Content-Type": "application/json;charset=UTF-8"
                    }
                }
            )
        _merge_dict(args, self.kwargs.copy())
        _merge_dict(args, kwargs)
        response = self.session.put(self.make_url(endpoint), **args)

        decoded_response = _decode_response(response)

        if return_response:
            return decoded_response, response
        return decoded_response

    def post(self, endpoint, return_response=False, **kwargs):
        """ Send HTTP POST to the endpoint.

        :arg str endpoint: The endpoint to send to.

        :returns:
            JSON decoded result.

        :raises:
            requests.RequestException on timeout or connection error.

        """
        args = {}
        if "data" in kwargs or "json" in kwargs:
            _merge_dict(
                args, {
                    "headers": {
                        "Content-Type": "application/json;charset=UTF-8"
                    }
                }
            )
        _merge_dict(args, self.kwargs.copy())
        _merge_dict(args, kwargs)
        response = self.session.post(self.make_url(endpoint), **args)

        decoded_response = _decode_response(response)

        if return_response:
            return decoded_response, response
        return decoded_response

    def delete(self, endpoint, return_response=False, **kwargs):
        """ Send HTTP DELETE to the endpoint.

        :arg str endpoint: The endpoint to send to.

        :returns:
            JSON decoded result.

        :raises:
            requests.RequestException on timeout or connection error.

        """
        args = {}
        if "data" in kwargs or "json" in kwargs:
            _merge_dict(
                args, {
                    "headers": {
                        "Content-Type": "application/json;charset=UTF-8"
                    }
                }
            )
        _merge_dict(args, self.kwargs.copy())
        _merge_dict(args, kwargs)
        response = self.session.delete(self.make_url(endpoint), **args)

        decoded_response = _decode_response(response)

        if return_response:
            return decoded_response, response
        return decoded_response

    def review(self, change_id, revision, review):
        """ Submit a review.

        :arg str change_id: The change ID.
        :arg str revision: The revision.
        :arg str review: The review details as a :class:`GerritReview`.

        :returns:
            JSON decoded result.

        :raises:
            requests.RequestException on timeout or connection error.

        """

        endpoint = "changes/%s/revisions/%s/review" % (change_id, revision)
        self.post(endpoint, data=str(review))

class GerritReview(object):

    """ Encapsulation of a Gerrit review.

    :arg str message: (optional) Cover message.
    :arg dict labels: (optional) Review labels.
    :arg dict comments: (optional) Inline comments.

    """

    def __init__(self, message=None, labels=None, comments=None):
        self.message = message if message else ""
        if labels:
            if not isinstance(labels, dict):
                raise ValueError("labels must be a dict.")
            self.labels = labels
        else:
            self.labels = {}
        if comments:
            if not isinstance(comments, list):
                raise ValueError("comments must be a list.")
            self.comments = {}
            self.add_comments(comments)
        else:
            self.comments = {}

    def set_message(self, message):
        """ Set review cover message.

        :arg str message: Cover message.

        """
        self.message = message

    def add_labels(self, labels):
        """ Add labels.

        :arg dict labels: Labels to add, for example

        Usage::

            add_labels({'Verified': 1,
                        'Code-Review': -1})

        """
        self.labels.update(labels)

    def add_comments(self, comments):
        """ Add inline comments.

        :arg dict comments: Comments to add.

        Usage::

            add_comments([{'filename': 'Makefile',
                           'line': 10,
                           'message': 'inline message'}])

            add_comments([{'filename': 'Makefile',
                           'range': {'start_line': 0,
                                     'start_character': 1,
                                     'end_line': 0,
                                     'end_character': 5},
                           'message': 'inline message'}])

        """
        for comment in comments:
            if 'filename' and 'message' in list(comment.keys()):
                msg = {}
                if 'range' in list(comment.keys()):
                    msg = {"range": comment['range'],
                           "message": comment['message']}
                elif 'line' in list(comment.keys()):
                    msg = {"line": comment['line'],
                           "message": comment['message']}
                else:
                    continue
                file_comment = {comment['filename']: [msg]}
                if self.comments:
                    if comment['filename'] in list(self.comments.keys()):
                        self.comments[comment['filename']].append(msg)
                    else:
                        self.comments.update(file_comment)
                else:
                    self.comments.update(file_comment)

    def __str__(self):
        review_input = {}
        if self.message:
            review_input.update({'message': self.message})
        if self.labels:
            review_input.update({'labels': self.labels})
        if self.comments:
            review_input.update({'comments': self.comments})
        return json.dumps(review_input, sort_keys=True)
<commit_msg>Fixes #10: Fix a bug preventing file upload in PUT and POST<commit_after># The MIT License
#
# Copyright 2013 Sony Mobile Communications. All rights reserved.
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.

""" Interface to the Gerrit REST API. """

import json
import logging
import requests

GERRIT_MAGIC_JSON_PREFIX = ")]}\'\n"
GERRIT_AUTH_SUFFIX = "/a"

def _decode_response(response):
    """ Strip off Gerrit's magic prefix and decode a response.

    :returns:
        Decoded JSON content as a dict, or raw text if content could not be
        decoded as JSON.

    :raises:
        requests.HTTPError if the response contains an HTTP error status code.

    """
    content = response.content.strip()
    if response.encoding:
        content = content.decode(response.encoding)
    response.raise_for_status()
    content_type = response.headers.get('content-type', '')
    if content_type.split(';')[0] != 'application/json':
        return content
    if content.startswith(GERRIT_MAGIC_JSON_PREFIX):
        content = content[len(GERRIT_MAGIC_JSON_PREFIX):]
    try:
        return json.loads(content)
    except ValueError:
        logging.error('Invalid json content: %s' % content)
        raise

def _merge_dict(result, overrides):
    """ Deep-merge dictionaries.

    :arg dict result: The resulting dictionary
    :arg dict overrides: Dictionay being merged into the result

    :returns:
        The resulting dictionary

    """
    for key in overrides:
        if (
            key in result and
            isinstance(result[key], dict) and
            isinstance(overrides[key], dict)
        ):
            _merge_dict(result[key], overrides[key])
        else:
            result[key] = overrides[key]
    return result

class GerritRestAPI(object):

    """ Interface to the Gerrit REST API.

    :arg str url: The full URL to the server, including the `http(s)://` prefix.
        If `auth` is given, `url` will be automatically adjusted to include
        Gerrit's authentication suffix.
    :arg auth: (optional) Authentication handler.  Must be derived from
        `requests.auth.AuthBase`.
    :arg boolean verify: (optional) Set to False to disable verification of
        SSL certificates.

    """

    def __init__(self, url, auth=None, verify=True):
        headers = {'Accept': 'application/json',
                   'Accept-Encoding': 'gzip'}
        self.kwargs = {'auth': auth,
                       'verify': verify,
                       'headers': headers}
        self.url = url.rstrip('/')
        self.session = requests.session()

        if auth:
            if not isinstance(auth, requests.auth.AuthBase):
                raise ValueError('Invalid auth type; must be derived '
                                 'from requests.auth.AuthBase')

            if not self.url.endswith(GERRIT_AUTH_SUFFIX):
                self.url += GERRIT_AUTH_SUFFIX
        else:
            if self.url.endswith(GERRIT_AUTH_SUFFIX):
                self.url = self.url[: - len(GERRIT_AUTH_SUFFIX)]

        if not self.url.endswith('/'):
            self.url += '/'

    def make_url(self, endpoint):
        """ Make the full url for the endpoint.

        :arg str endpoint: The endpoint.

        :returns:
            The full url.

        """
        endpoint = endpoint.lstrip('/')
        return self.url + endpoint

    def get(self, endpoint, return_response=False, **kwargs):
        """ Send HTTP GET to the endpoint.

        :arg str endpoint: The endpoint to send to.
        :arg bool return_response: If true will also return the response

        :returns:
            JSON decoded result.

        :raises:
            requests.RequestException on timeout or connection error.

        """
        kwargs.update(self.kwargs.copy())
        response = self.session.get(self.make_url(endpoint), **kwargs)

        decoded_response = _decode_response(response)

        if return_response:
            return decoded_response, response
        return decoded_response

    def put(self, endpoint, return_response=False, **kwargs):
        """ Send HTTP PUT to the endpoint.

        :arg str endpoint: The endpoint to send to.

        :returns:
            JSON decoded result.

        :raises:
            requests.RequestException on timeout or connection error.

        """
        args = {}
        if ("data" in kwargs and isinstance(kwargs["data"], dict)) or \
                "json" in kwargs:
            _merge_dict(
                args, {
                    "headers": {
                        "Content-Type": "application/json;charset=UTF-8"
                    }
                }
            )
        _merge_dict(args, self.kwargs.copy())
        _merge_dict(args, kwargs)
        response = self.session.put(self.make_url(endpoint), **args)

        decoded_response = _decode_response(response)

        if return_response:
            return decoded_response, response
        return decoded_response

    def post(self, endpoint, return_response=False, **kwargs):
        """ Send HTTP POST to the endpoint.

        :arg str endpoint: The endpoint to send to.

        :returns:
            JSON decoded result.

        :raises:
            requests.RequestException on timeout or connection error.

        """
        args = {}
        if ("data" in kwargs and isinstance(kwargs["data"], dict)) or \
                "json" in kwargs:
            _merge_dict(
                args, {
                    "headers": {
                        "Content-Type": "application/json;charset=UTF-8"
                    }
                }
            )
        _merge_dict(args, self.kwargs.copy())
        _merge_dict(args, kwargs)
        response = self.session.post(self.make_url(endpoint), **args)

        decoded_response = _decode_response(response)

        if return_response:
            return decoded_response, response
        return decoded_response

    def delete(self, endpoint, return_response=False, **kwargs):
        """ Send HTTP DELETE to the endpoint.

        :arg str endpoint: The endpoint to send to.

        :returns:
            JSON decoded result.

        :raises:
            requests.RequestException on timeout or connection error.

        """
        args = {}
        if "data" in kwargs or "json" in kwargs:
            _merge_dict(
                args, {
                    "headers": {
                        "Content-Type": "application/json;charset=UTF-8"
                    }
                }
            )
        _merge_dict(args, self.kwargs.copy())
        _merge_dict(args, kwargs)
        response = self.session.delete(self.make_url(endpoint), **args)

        decoded_response = _decode_response(response)

        if return_response:
            return decoded_response, response
        return decoded_response

    def review(self, change_id, revision, review):
        """ Submit a review.

        :arg str change_id: The change ID.
        :arg str revision: The revision.
        :arg str review: The review details as a :class:`GerritReview`.

        :returns:
            JSON decoded result.

        :raises:
            requests.RequestException on timeout or connection error.

        """

        endpoint = "changes/%s/revisions/%s/review" % (change_id, revision)
        self.post(endpoint, data=str(review))

class GerritReview(object):

    """ Encapsulation of a Gerrit review.

    :arg str message: (optional) Cover message.
    :arg dict labels: (optional) Review labels.
    :arg dict comments: (optional) Inline comments.

    """

    def __init__(self, message=None, labels=None, comments=None):
        self.message = message if message else ""
        if labels:
            if not isinstance(labels, dict):
                raise ValueError("labels must be a dict.")
            self.labels = labels
        else:
            self.labels = {}
        if comments:
            if not isinstance(comments, list):
                raise ValueError("comments must be a list.")
            self.comments = {}
            self.add_comments(comments)
        else:
            self.comments = {}

    def set_message(self, message):
        """ Set review cover message.

        :arg str message: Cover message.

        """
        self.message = message

    def add_labels(self, labels):
        """ Add labels.

        :arg dict labels: Labels to add, for example

        Usage::

            add_labels({'Verified': 1,
                        'Code-Review': -1})

        """
        self.labels.update(labels)

    def add_comments(self, comments):
        """ Add inline comments.

        :arg dict comments: Comments to add.

        Usage::

            add_comments([{'filename': 'Makefile',
                           'line': 10,
                           'message': 'inline message'}])

            add_comments([{'filename': 'Makefile',
                           'range': {'start_line': 0,
                                     'start_character': 1,
                                     'end_line': 0,
                                     'end_character': 5},
                           'message': 'inline message'}])

        """
        for comment in comments:
            if 'filename' and 'message' in list(comment.keys()):
                msg = {}
                if 'range' in list(comment.keys()):
                    msg = {"range": comment['range'],
                           "message": comment['message']}
                elif 'line' in list(comment.keys()):
                    msg = {"line": comment['line'],
                           "message": comment['message']}
                else:
                    continue
                file_comment = {comment['filename']: [msg]}
                if self.comments:
                    if comment['filename'] in list(self.comments.keys()):
                        self.comments[comment['filename']].append(msg)
                    else:
                        self.comments.update(file_comment)
                else:
                    self.comments.update(file_comment)

    def __str__(self):
        review_input = {}
        if self.message:
            review_input.update({'message': self.message})
        if self.labels:
            review_input.update({'labels': self.labels})
        if self.comments:
            review_input.update({'comments': self.comments})
        return json.dumps(review_input, sort_keys=True)
<|endoftext|>


<commit_before># ----------------------------------------------------------------------------
# pyglet
# Copyright (c) 2006-2008 Alex Holkner
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
#  * Redistributions of source code must retain the above copyright
#    notice, this list of conditions and the following disclaimer.
#  * Redistributions in binary form must reproduce the above copyright
#    notice, this list of conditions and the following disclaimer in
#    the documentation and/or other materials provided with the
#    distribution.
#  * Neither the name of pyglet nor the names of its
#    contributors may be used to endorse or promote products
#    derived from this software without specific prior written
#    permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
# ----------------------------------------------------------------------------

'''
'''

__docformat__ = 'restructuredtext'
__version__ = '$Id$'

import os.path

from pyglet.gl import *
from pyglet.image import *
from pyglet.image.codecs import *

import Image

class PILImageDecoder(ImageDecoder):
    def get_file_extensions(self):
        # Only most common ones shown here
        return ['.bmp', '.cur', '.gif', '.ico', '.jpg', '.jpeg', '.pcx', '.png',
                '.tga', '.tif', '.tiff', '.xbm', '.xpm']

    def decode(self, file, filename):
        try:
            image = Image.open(file)
        except Exception, e:
            raise ImageDecodeException(
                'PIL cannot read %r: %s' % (filename or file, e))

        image = image.transpose(Image.FLIP_TOP_BOTTOM)

        # Convert bitmap and palette images to component
        if image.mode in ('1', 'P'):
            image = image.convert()

        if image.mode not in ('L', 'LA', 'RGB', 'RGBA'):
            raise ImageDecodeException('Unsupported mode "%s"' % image.mode)
        type = GL_UNSIGNED_BYTE
        width, height = image.size

        return ImageData(width, height, image.mode, image.tostring())

class PILImageEncoder(ImageEncoder):
    def get_file_extensions(self):
        # Most common only
        return ['.bmp', '.eps', '.gif', '.jpg', '.jpeg',
                '.pcx', '.png', '.ppm', '.tiff', '.xbm']

    def encode(self, image, file, filename):
        # File format is guessed from filename extension, otherwise defaults
        # to PNG.
        pil_format = (filename and os.path.splitext(filename)[1][1:]) or 'png'

        if pil_format.lower() == 'jpg':
            pil_format = 'JPEG'

        image = image.get_image_data()
        format = image.format
        if format != 'RGB':
            # Only save in RGB or RGBA formats.
            format = 'RGBA'
        pitch = -(image.width * len(format))

        # Note: Don't try and use frombuffer(..); different versions of
        # PIL will orient the image differently.
        pil_image = Image.fromstring(
            format, (image.width, image.height), image.get_data(format, pitch))

        try:
            pil_image.save(file, pil_format)
        except Exception, e:
            raise ImageEncodeException(e)

def get_decoders():
    return [PILImageDecoder()]

def get_encoders():
    return [PILImageEncoder()]
<commit_msg>Fix issue 551<commit_after># ----------------------------------------------------------------------------
# pyglet
# Copyright (c) 2006-2008 Alex Holkner
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
#  * Redistributions of source code must retain the above copyright
#    notice, this list of conditions and the following disclaimer.
#  * Redistributions in binary form must reproduce the above copyright
#    notice, this list of conditions and the following disclaimer in
#    the documentation and/or other materials provided with the
#    distribution.
#  * Neither the name of pyglet nor the names of its
#    contributors may be used to endorse or promote products
#    derived from this software without specific prior written
#    permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
# ----------------------------------------------------------------------------

'''
'''

__docformat__ = 'restructuredtext'
__version__ = '$Id$'

import os.path

from pyglet.gl import *
from pyglet.image import *
from pyglet.image.codecs import *

try:
    import Image
except ImportError:
    from PIL import Image

class PILImageDecoder(ImageDecoder):
    def get_file_extensions(self):
        # Only most common ones shown here
        return ['.bmp', '.cur', '.gif', '.ico', '.jpg', '.jpeg', '.pcx', '.png',
                '.tga', '.tif', '.tiff', '.xbm', '.xpm']

    def decode(self, file, filename):
        try:
            image = Image.open(file)
        except Exception, e:
            raise ImageDecodeException(
                'PIL cannot read %r: %s' % (filename or file, e))

        image = image.transpose(Image.FLIP_TOP_BOTTOM)

        # Convert bitmap and palette images to component
        if image.mode in ('1', 'P'):
            image = image.convert()

        if image.mode not in ('L', 'LA', 'RGB', 'RGBA'):
            raise ImageDecodeException('Unsupported mode "%s"' % image.mode)
        type = GL_UNSIGNED_BYTE
        width, height = image.size

        return ImageData(width, height, image.mode, image.tostring())

class PILImageEncoder(ImageEncoder):
    def get_file_extensions(self):
        # Most common only
        return ['.bmp', '.eps', '.gif', '.jpg', '.jpeg',
                '.pcx', '.png', '.ppm', '.tiff', '.xbm']

    def encode(self, image, file, filename):
        # File format is guessed from filename extension, otherwise defaults
        # to PNG.
        pil_format = (filename and os.path.splitext(filename)[1][1:]) or 'png'

        if pil_format.lower() == 'jpg':
            pil_format = 'JPEG'

        image = image.get_image_data()
        format = image.format
        if format != 'RGB':
            # Only save in RGB or RGBA formats.
            format = 'RGBA'
        pitch = -(image.width * len(format))

        # Note: Don't try and use frombuffer(..); different versions of
        # PIL will orient the image differently.
        pil_image = Image.fromstring(
            format, (image.width, image.height), image.get_data(format, pitch))

        try:
            pil_image.save(file, pil_format)
        except Exception, e:
            raise ImageEncodeException(e)

def get_decoders():
    return [PILImageDecoder()]

def get_encoders():
    return [PILImageEncoder()]
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-
"""
    pygments.lexers.varnish
    ~~~~~~~~~~~~~~~~~~~~~~~

    Lexers for Varnish configuration

    :copyright: Copyright 2006-2015 by the Pygments team, see AUTHORS.
    :license: BSD, see LICENSE for details.
"""

from pygments.lexer import RegexLexer, include, bygroups, using, this, \
    inherit, words
from pygments.token import Text, Comment, Operator, Keyword, Name, String, \
    Number, Punctuation, Literal

__all__ = ['VCLLexer', 'VCLSnippetLexer']

class VCLLexer(RegexLexer):
    """
    For Varnish Configuration Language (VCL).

    .. versionadded:: 2.2
    """
    name = 'VCL'
    aliases = ['vcl']
    filenames = ['*.vcl']
    mimetypes = ['text/x-vclsrc']

    def analyse_text(text):
        # If the very first line is 'vcl 4.0;' it's pretty much guaranteed
        # that this is VCL
        if text.startswith('vcl 4.0;'):
            return 1.0
        # Skip over comments and blank lines
        # This is accurate enough that returning 0.9 is reasonable.
        # Almost no VCL files start without some comments.
        elif '\nvcl 4\.0;' in text[:1000]:
            return 0.9

    tokens = {
        'probe': [
            include('whitespace'),
            include('comments'),
            (r'(\.\w+)(\s*=\s*)([^;]*)(;)',
             bygroups(Name.Attribute, Operator, using(this), Punctuation)),
            (r'\}', Punctuation, '#pop'),
        ],
        'acl': [
            include('whitespace'),
            include('comments'),
            (r'[!/]+', Operator),
            (r';', Punctuation),
            (r'\d+', Number),
            (r'\}', Punctuation, '#pop'),
        ],
        'backend': [
            include('whitespace'),
            (r'(\.probe)(\s*=\s*)(\w+)(;)',
             bygroups(Name.Attribute, Operator, Name.Variable.Global, Punctuation)),
            (r'(\.probe)(\s*=\s*)(\{)',
             bygroups(Name.Attribute, Operator, Punctuation), 'probe'),
            (r'(\.\w+\b)(\s*=\s*)([^;]*)(\s*;)',
             bygroups(Name.Attribute, Operator, using(this), Punctuation)),
            (r'\{', Punctuation, '#push'),
            (r'\}', Punctuation, '#pop'),
        ],
        'statements': [
            (r'(\d\.)?\d+[sdwhmy]', Literal.Date),
            (r'(\d\.)?\d+ms', Literal.Date),
            (r'(vcl_pass|vcl_hash|vcl_hit|vcl_init|vcl_backend_fetch|vcl_pipe|'
             r'vcl_backend_response|vcl_synth|vcl_deliver|vcl_backend_error|'
             r'vcl_fini|vcl_recv|vcl_purge|vcl_miss)\b', Name.Function),
            (r'(pipe|retry|hash|synth|deliver|purge|abandon|lookup|pass|fail|ok|'
             r'miss|fetch|restart)\b', Name.Constant),
            (r'(beresp|obj|resp|req|req_top|bereq)\.http\.[a-zA-Z_-]+\b', Name.Variable),
            (words((
                'obj.status', 'req.hash_always_miss', 'beresp.backend', 'req.esi_level',
                'req.can_gzip', 'beresp.ttl', 'obj.uncacheable', 'req.ttl', 'obj.hits',
                'client.identity', 'req.hash_ignore_busy', 'obj.reason', 'req.xid',
                'req_top.proto', 'beresp.age', 'obj.proto', 'obj.age', 'local.ip',
                'beresp.uncacheable', 'req.method', 'beresp.backend.ip', 'now',
                'obj.grace', 'req.restarts', 'beresp.keep', 'req.proto', 'resp.proto',
                'bereq.xid', 'bereq.between_bytes_timeout', 'req.esi',
                'bereq.first_byte_timeout', 'bereq.method', 'bereq.connect_timeout',
                'beresp.do_gzip',  'resp.status', 'beresp.do_gunzip',
                'beresp.storage_hint', 'resp.is_streaming', 'beresp.do_stream',
                'req_top.method', 'bereq.backend', 'beresp.backend.name', 'beresp.status',
                'req.url', 'obj.keep', 'obj.ttl', 'beresp.reason', 'bereq.retries',
                'resp.reason', 'bereq.url', 'beresp.do_esi', 'beresp.proto', 'client.ip',
                'bereq.proto', 'server.hostname', 'remote.ip', 'req.backend_hint',
                'server.identity', 'req_top.url', 'beresp.grace', 'beresp.was_304',
                'server.ip', 'bereq.uncacheable', 'now'), suffix=r'\b'),
             Name.Variable),
            (r'[!%&+*\-,/<.}{>=|~]+', Operator),
            (r'[();]', Punctuation),

            (r'[,]+', Punctuation),
            (words(('include', 'hash_data', 'regsub', 'regsuball', 'if', 'else',
                    'elsif', 'elif', 'synth', 'synthetic', 'ban', 'synth',
                    'return', 'set', 'unset', 'import', 'include', 'new',
                    'rollback', 'call'), suffix=r'\b'),
             Keyword),
            (r'storage\.\w+\.\w+\b', Name.Variable),
            (words(('true', 'false')), Name.Builtin),
            (r'\d+\b', Number),
            (r'(backend)(\s+\w+)(\s*\{)',
             bygroups(Keyword, Name.Variable.Global, Punctuation), 'backend'),
            (r'(probe\s)(\s*\w+\s)(\{)',
             bygroups(Keyword, Name.Variable.Global, Punctuation), 'probe'),
            (r'(acl\s)(\s*\w+\s)(\{)',
             bygroups(Keyword, Name.Variable.Global, Punctuation), 'acl'),
            (r'(vcl )(4.0)(;)$',
             bygroups(Keyword.Reserved, Name.Constant, Punctuation)),
            (r'(sub\s+)([a-zA-Z]\w*)(\s*\{)',
                bygroups(Keyword, Name.Function, Punctuation)),
            (r'([a-zA-Z_]\w*)'
             r'(\.)'
             r'([a-zA-Z_]\w*)'
             r'(\s*\(.*\))',
             bygroups(Name.Function, Punctuation, Name.Function, using(this))),
            ('[a-zA-Z_]\w*', Name),
            ],
        'comment': [
            (r'[^*/]+', Comment.Multiline),
            (r'/\*', Comment.Multiline, '#push'),
            (r'\*/', Comment.Multiline, '#pop'),
            (r'[*/]', Comment.Multiline),
            ],
        'comments': [
            (r'#.*$', Comment),
            (r'/\*', Comment.Multiline, 'comment'),
            (r'//.*$', Comment),
        ],
        'string': [
            (r'"', String, '#pop'),
            (r'[^"\n]+', String),  # all other characters
        ],
        'multistring': [
            (r'[^"}]', String),
            (r'"\}', String, '#pop'),
            (r'["}]', String),
        ],
        'whitespace': [
            (r'L?"', String, 'string'),
            (r'\{"', String, 'multistring'),
            (r'\n', Text),
            (r'\s+', Text),
            (r'\\\n', Text),  # line continuation
        ],
        'root': [
            include('whitespace'),
            include('comments'),
            include('statements'),
            (r'\s+', Text),
        ],
    }

class VCLSnippetLexer(VCLLexer):
    """
    For Varnish Configuration Language snippets.

    .. versionadded:: 2.2
    """
    name = 'VCLSnippets'
    aliases = ['vclsnippets', 'vclsnippet']
    mimetypes = ['text/x-vclsnippet']
    filenames = []

    tokens = {
        'snippetspre': [
            (r'\.\.\.+', Comment),
            (r'(bereq|req|req_top|resp|beresp|obj|client|server|local|remote|'
             r'storage)($|\.\*)', Name.Variable),
        ],
        'snippetspost': [
            (r'(backend)\b', Keyword.Reserved),
        ],
        'root': [
            include('snippetspre'),
            inherit,
            include('snippetspost'),
        ],
    }
<commit_msg>Add back VCL snippet lexer analyse_text.<commit_after># -*- coding: utf-8 -*-
"""
    pygments.lexers.varnish
    ~~~~~~~~~~~~~~~~~~~~~~~

    Lexers for Varnish configuration

    :copyright: Copyright 2006-2015 by the Pygments team, see AUTHORS.
    :license: BSD, see LICENSE for details.
"""

from pygments.lexer import RegexLexer, include, bygroups, using, this, \
    inherit, words
from pygments.token import Text, Comment, Operator, Keyword, Name, String, \
    Number, Punctuation, Literal

__all__ = ['VCLLexer', 'VCLSnippetLexer']

class VCLLexer(RegexLexer):
    """
    For Varnish Configuration Language (VCL).

    .. versionadded:: 2.2
    """
    name = 'VCL'
    aliases = ['vcl']
    filenames = ['*.vcl']
    mimetypes = ['text/x-vclsrc']

    def analyse_text(text):
        # If the very first line is 'vcl 4.0;' it's pretty much guaranteed
        # that this is VCL
        if text.startswith('vcl 4.0;'):
            return 1.0
        # Skip over comments and blank lines
        # This is accurate enough that returning 0.9 is reasonable.
        # Almost no VCL files start without some comments.
        elif '\nvcl 4\.0;' in text[:1000]:
            return 0.9

    tokens = {
        'probe': [
            include('whitespace'),
            include('comments'),
            (r'(\.\w+)(\s*=\s*)([^;]*)(;)',
             bygroups(Name.Attribute, Operator, using(this), Punctuation)),
            (r'\}', Punctuation, '#pop'),
        ],
        'acl': [
            include('whitespace'),
            include('comments'),
            (r'[!/]+', Operator),
            (r';', Punctuation),
            (r'\d+', Number),
            (r'\}', Punctuation, '#pop'),
        ],
        'backend': [
            include('whitespace'),
            (r'(\.probe)(\s*=\s*)(\w+)(;)',
             bygroups(Name.Attribute, Operator, Name.Variable.Global, Punctuation)),
            (r'(\.probe)(\s*=\s*)(\{)',
             bygroups(Name.Attribute, Operator, Punctuation), 'probe'),
            (r'(\.\w+\b)(\s*=\s*)([^;]*)(\s*;)',
             bygroups(Name.Attribute, Operator, using(this), Punctuation)),
            (r'\{', Punctuation, '#push'),
            (r'\}', Punctuation, '#pop'),
        ],
        'statements': [
            (r'(\d\.)?\d+[sdwhmy]', Literal.Date),
            (r'(\d\.)?\d+ms', Literal.Date),
            (r'(vcl_pass|vcl_hash|vcl_hit|vcl_init|vcl_backend_fetch|vcl_pipe|'
             r'vcl_backend_response|vcl_synth|vcl_deliver|vcl_backend_error|'
             r'vcl_fini|vcl_recv|vcl_purge|vcl_miss)\b', Name.Function),
            (r'(pipe|retry|hash|synth|deliver|purge|abandon|lookup|pass|fail|ok|'
             r'miss|fetch|restart)\b', Name.Constant),
            (r'(beresp|obj|resp|req|req_top|bereq)\.http\.[a-zA-Z_-]+\b', Name.Variable),
            (words((
                'obj.status', 'req.hash_always_miss', 'beresp.backend', 'req.esi_level',
                'req.can_gzip', 'beresp.ttl', 'obj.uncacheable', 'req.ttl', 'obj.hits',
                'client.identity', 'req.hash_ignore_busy', 'obj.reason', 'req.xid',
                'req_top.proto', 'beresp.age', 'obj.proto', 'obj.age', 'local.ip',
                'beresp.uncacheable', 'req.method', 'beresp.backend.ip', 'now',
                'obj.grace', 'req.restarts', 'beresp.keep', 'req.proto', 'resp.proto',
                'bereq.xid', 'bereq.between_bytes_timeout', 'req.esi',
                'bereq.first_byte_timeout', 'bereq.method', 'bereq.connect_timeout',
                'beresp.do_gzip',  'resp.status', 'beresp.do_gunzip',
                'beresp.storage_hint', 'resp.is_streaming', 'beresp.do_stream',
                'req_top.method', 'bereq.backend', 'beresp.backend.name', 'beresp.status',
                'req.url', 'obj.keep', 'obj.ttl', 'beresp.reason', 'bereq.retries',
                'resp.reason', 'bereq.url', 'beresp.do_esi', 'beresp.proto', 'client.ip',
                'bereq.proto', 'server.hostname', 'remote.ip', 'req.backend_hint',
                'server.identity', 'req_top.url', 'beresp.grace', 'beresp.was_304',
                'server.ip', 'bereq.uncacheable', 'now'), suffix=r'\b'),
             Name.Variable),
            (r'[!%&+*\-,/<.}{>=|~]+', Operator),
            (r'[();]', Punctuation),

            (r'[,]+', Punctuation),
            (words(('include', 'hash_data', 'regsub', 'regsuball', 'if', 'else',
                    'elsif', 'elif', 'synth', 'synthetic', 'ban', 'synth',
                    'return', 'set', 'unset', 'import', 'include', 'new',
                    'rollback', 'call'), suffix=r'\b'),
             Keyword),
            (r'storage\.\w+\.\w+\b', Name.Variable),
            (words(('true', 'false')), Name.Builtin),
            (r'\d+\b', Number),
            (r'(backend)(\s+\w+)(\s*\{)',
             bygroups(Keyword, Name.Variable.Global, Punctuation), 'backend'),
            (r'(probe\s)(\s*\w+\s)(\{)',
             bygroups(Keyword, Name.Variable.Global, Punctuation), 'probe'),
            (r'(acl\s)(\s*\w+\s)(\{)',
             bygroups(Keyword, Name.Variable.Global, Punctuation), 'acl'),
            (r'(vcl )(4.0)(;)$',
             bygroups(Keyword.Reserved, Name.Constant, Punctuation)),
            (r'(sub\s+)([a-zA-Z]\w*)(\s*\{)',
                bygroups(Keyword, Name.Function, Punctuation)),
            (r'([a-zA-Z_]\w*)'
             r'(\.)'
             r'([a-zA-Z_]\w*)'
             r'(\s*\(.*\))',
             bygroups(Name.Function, Punctuation, Name.Function, using(this))),
            ('[a-zA-Z_]\w*', Name),
            ],
        'comment': [
            (r'[^*/]+', Comment.Multiline),
            (r'/\*', Comment.Multiline, '#push'),
            (r'\*/', Comment.Multiline, '#pop'),
            (r'[*/]', Comment.Multiline),
            ],
        'comments': [
            (r'#.*$', Comment),
            (r'/\*', Comment.Multiline, 'comment'),
            (r'//.*$', Comment),
        ],
        'string': [
            (r'"', String, '#pop'),
            (r'[^"\n]+', String),  # all other characters
        ],
        'multistring': [
            (r'[^"}]', String),
            (r'"\}', String, '#pop'),
            (r'["}]', String),
        ],
        'whitespace': [
            (r'L?"', String, 'string'),
            (r'\{"', String, 'multistring'),
            (r'\n', Text),
            (r'\s+', Text),
            (r'\\\n', Text),  # line continuation
        ],
        'root': [
            include('whitespace'),
            include('comments'),
            include('statements'),
            (r'\s+', Text),
        ],
    }

class VCLSnippetLexer(VCLLexer):
    """
    For Varnish Configuration Language snippets.

    .. versionadded:: 2.2
    """
    name = 'VCLSnippets'
    aliases = ['vclsnippets', 'vclsnippet']
    mimetypes = ['text/x-vclsnippet']
    filenames = []

    def analyse_text(text):
        # override method inherited from VCLLexer
        return 0

    tokens = {
        'snippetspre': [
            (r'\.\.\.+', Comment),
            (r'(bereq|req|req_top|resp|beresp|obj|client|server|local|remote|'
             r'storage)($|\.\*)', Name.Variable),
        ],
        'snippetspost': [
            (r'(backend)\b', Keyword.Reserved),
        ],
        'root': [
            include('snippetspre'),
            inherit,
            include('snippetspost'),
        ],
    }
<|endoftext|>


<commit_before>import theano
import numpy

def make_name(variable, anon = "anonymous_variable"):
    """
    If variable has a name, returns that name.
    Otherwise, returns anon
    """

    if hasattr(variable,'name') and variable.name is not None:
        return variable.name

    return anon

def sharedX(value, name=None, borrow=False):
    """Transform value into a shared variable of type floatX"""
    return theano.shared(theano._asarray(value, dtype=theano.config.floatX),
                         name=name,
                         borrow=borrow)

def as_floatX(variable):
    """Casts a given variable into dtype config.floatX
        numpy ndarrays will remain numpy ndarrays
        all other types will be treated as theano tensors"""

    if isinstance(variable, numpy.ndarray):
        return numpy.cast[theano.config.floatX](variable)

    return theano.tensor.cast(variable, theano.config.floatX)

def subdict(d, keys):
    """ Create a subdictionary of d with the keys in keys """
    result = {}
    for key in keys:
        if key in d: result[key] = d[key]
    return result

"""
doesn't make sense to auto-import utlc code in a generic
pylearn2 module, especially
now that no one will probably use the utlc stuff ever again
from pylearn2.utils.utlc import (
        subdict,
        safe_update,
        getboth,
        load_data,
        save_submission,
        create_submission,
        compute_alc,
        lookup_alc,
        )"""

"""from pylearn2.utils.datasets import (
        do_3d_scatter,
        save_plot,
        filter_labels,
        filter_nonzero,
        nonzero_features,
        BatchIterator,
        blend,
        minibatch_map,
        )""" # this is making cluster jobs crash, and seems like kind of a lot of stuff to import by default anyway
<commit_msg>made as_floatX treat floats like ndarrays<commit_after>import theano
import numpy

def make_name(variable, anon = "anonymous_variable"):
    """
    If variable has a name, returns that name.
    Otherwise, returns anon
    """

    if hasattr(variable,'name') and variable.name is not None:
        return variable.name

    return anon

def sharedX(value, name=None, borrow=False):
    """Transform value into a shared variable of type floatX"""
    return theano.shared(theano._asarray(value, dtype=theano.config.floatX),
                         name=name,
                         borrow=borrow)

def as_floatX(variable):
    """Casts a given variable into dtype config.floatX
        numpy ndarrays will remain numpy ndarrays
        python floats will become 0-D ndarrays
        all other types will be treated as theano tensors"""

    if isinstance(variable, float):
        return numpy.cast[theano.config.floatX](variable)

    if isinstance(variable, numpy.ndarray):
        return numpy.cast[theano.config.floatX](variable)

    return theano.tensor.cast(variable, theano.config.floatX)

def subdict(d, keys):
    """ Create a subdictionary of d with the keys in keys """
    result = {}
    for key in keys:
        if key in d: result[key] = d[key]
    return result

"""
doesn't make sense to auto-import utlc code in a generic
pylearn2 module, especially
now that no one will probably use the utlc stuff ever again
from pylearn2.utils.utlc import (
        subdict,
        safe_update,
        getboth,
        load_data,
        save_submission,
        create_submission,
        compute_alc,
        lookup_alc,
        )"""

"""from pylearn2.utils.datasets import (
        do_3d_scatter,
        save_plot,
        filter_labels,
        filter_nonzero,
        nonzero_features,
        BatchIterator,
        blend,
        minibatch_map,
        )""" # this is making cluster jobs crash, and seems like kind of a lot of stuff to import by default anyway
<|endoftext|>


<commit_before>from django.conf.urls import patterns, include, url

# Uncomment the next two lines to enable the admin:
# from django.contrib import admin
# admin.autodiscover()

urlpatterns = patterns(
    '',
    # Examples:
    # url(r'^$', 'OEMS.views.home', name='home'),
    # url(r'^OEMS/', include('OEMS.foo.urls')),

    # Uncomment the admin/doc line below to enable admin documentation:
    # url(r'^admin/doc/', include('django.contrib.admindocs.urls')),

    # Uncomment the next line to enable the admin:
    # url(r'^admin/', include(admin.site.urls)),

    #Student related
    url(r'^student/$', 'student.views.index', name='student_index'),
    url(r'^student/dashboard/$', 'student.views.dashboard',
        name='student_dashboard'),
    url(r'^student/profile/$', 'student.views.profile',
        name='student_profile'),
    url(r'^student/profile/update/$', 'student.views.update_profile',
        name='update_student_profile'),
    url(r'^student/signin/$', 'student.views.sign_in',
        name='student_signin'),
    url(r'^student/signout/$', 'student.views.sign_out',
        name='student_signout'),

    #Student Experimnt Related
    url(r'^student/experiment/(?P<experiment_id>\d+)/$',
        'student.views.experiment_information',
        name='experiment_info_for_student'),
    url(r'^student/experiment_list/$',
        'student.views.experiment_list_for_picked_lesson',
        name='student_list_experiment'),

    #Student Lesson Related
    url(r'^student/lesson_list/$', 'student.views.has_pick_lesson_list',
        name='student_list_lesson'),
    url(r'^student/lesson/(?P<lesson_id>\d+)/$',
        'student.views.lesson_information',
        name='lesson_info_for_student'),
    url(r'^student/search/lesson/$', 'student.views.search_lesson',
        name='search_lesson'),
    url(r'^student/search_lesson/result/$',
        'student.views.search_lesson_result',
        name='search_lesson_result'),
    url(r'^student/lesson_pick/$', 'student.views.can_pick_lesson_list',
        name='student_pick'),
    url(r'^student/lesson_drop/$', 'student.views.can_drop_lesson_list',
        name='student_drop'),
    url(r'^student/lesson_pick/(?P<lesson_id>\d+)/$',
        'student.views.pick_lesson', name="lesson_pick"),
    url(r'^student/lesson_drop/(?P<lesson_id>\d+)/$',
        'student.views.drop_lesson', name="lesson_drop"),

    #Student Experiment Related
    url(r'^student/submit_report/(?P<experiment_id>\d+)$',
        'student.views.submit_report',
        name="submit_report"),
    url(r'^student/experiment/(?P<experiment_id>\d+)/$',
        'student.views.experiment_information',
        name="student_experiment_info"),

    #Student Experiment Report Related
    url(r'^tecaher/experiment_report/(?P<experiment_report_id>\d+)/evaluate/$',
        'teacher.views.experiment_report_evaluate',
        name='experiment_report_evaluate'),

    #Teacher Related
    url(r'^teacher/$', 'teacher.views.index', name='teacher_index'),
    url(r'^teacher/dashboard/$', 'teacher.views.dashboard',
        name='teacher_dashboard'),
    url(r'^teacher/signin/$', 'teacher.views.sign_in',
        name='teacher_signin'),
    url(r'^teacher/signout/$', 'teacher.views.sign_out',
        name='teacher_signout'),
    url(r'^teacher/profile/$', 'teacher.views.teacher_profile',
        name='teacher_profile'),

    #Teacher Lesson Category Related
    url(r'^teacher/create_lesson_category/$',
        'experiment.views.create_lesson_category',
        name='create_lesson_category'),
    url(r'^teacher/lesson_category_list/$',
        'experiment.views.lesson_category_list', name="category_list"),

    #Teacher Lesson Related
    url(r'^teacher/lesson/create/$', 'experiment.views.create_lesson',
        name='create_lesson'),
    url(r'^teacher/lesson/(?P<lesson_id>\d+)/$',
        'experiment.views.lesson_information', name="lesson_info"),
    url(r'^teacher/update_lesson/(?P<lesson_id>\d+)/$',
        'experiment.views.update_lesson', name='update_lesson'),
    url(r'^teacher/lesson/(?P<lesson_id>\d+)/delete/$',
        'experiment.views.delete_lesson', name='delete_lesson'),
    url(r'^teacher/lesson_list/$', 'experiment.views.lesson_list_all',
        name="teacher_lesson_list_all"),
    url(r'^teacher/lesson_list/(?P<category_id>\d+)/$',
        'experiment.views.lesson_list', name="teacher_lesson_list"),

    #Teacher Experiment Related
    url(r'^teacher/create_experiment/(?P<lesson_id>\d+)/$',
        'experiment.views.create_experiment', name="create_experiment"),
    url(r'^teacher/experiment/(?P<experiment_id>\d+)/$',
        'experiment.views.experiment_information', name="experiment_info"),
    url(r'^teacher/experiment/(?P<experiment_id>\d+)/delete/$',
        'experiment.views.delete_experiment', name='delete_experiment'),

    #Teacher Experiment Report Related
    url(r'^teacher/experiment/(?P<experiment_id>\d+)/modify/$',
        'experiment.views.experiment_modify', name='experiment_modify'),

)
<commit_msg>重构lesson category的url<commit_after>from django.conf.urls import patterns, include, url

# Uncomment the next two lines to enable the admin:
# from django.contrib import admin
# admin.autodiscover()

urlpatterns = patterns(
    '',
    # Examples:
    # url(r'^$', 'OEMS.views.home', name='home'),
    # url(r'^OEMS/', include('OEMS.foo.urls')),

    # Uncomment the admin/doc line below to enable admin documentation:
    # url(r'^admin/doc/', include('django.contrib.admindocs.urls')),

    # Uncomment the next line to enable the admin:
    # url(r'^admin/', include(admin.site.urls)),

    #Student related
    url(r'^student/$', 'student.views.index', name='student_index'),
    url(r'^student/dashboard/$', 'student.views.dashboard',
        name='student_dashboard'),
    url(r'^student/profile/$', 'student.views.profile',
        name='student_profile'),
    url(r'^student/profile/update/$', 'student.views.update_profile',
        name='update_student_profile'),
    url(r'^student/signin/$', 'student.views.sign_in',
        name='student_signin'),
    url(r'^student/signout/$', 'student.views.sign_out',
        name='student_signout'),

    #Student Experimnt Related
    url(r'^student/experiment/(?P<experiment_id>\d+)/$',
        'student.views.experiment_information',
        name='experiment_info_for_student'),
    url(r'^student/experiment_list/$',
        'student.views.experiment_list_for_picked_lesson',
        name='student_list_experiment'),

    #Student Lesson Related
    url(r'^student/lesson_list/$', 'student.views.has_pick_lesson_list',
        name='student_list_lesson'),
    url(r'^student/lesson/(?P<lesson_id>\d+)/$',
        'student.views.lesson_information',
        name='lesson_info_for_student'),
    url(r'^student/search/lesson/$', 'student.views.search_lesson',
        name='search_lesson'),
    url(r'^student/search_lesson/result/$',
        'student.views.search_lesson_result',
        name='search_lesson_result'),
    url(r'^student/lesson_pick/$', 'student.views.can_pick_lesson_list',
        name='student_pick'),
    url(r'^student/lesson_drop/$', 'student.views.can_drop_lesson_list',
        name='student_drop'),
    url(r'^student/lesson_pick/(?P<lesson_id>\d+)/$',
        'student.views.pick_lesson', name="lesson_pick"),
    url(r'^student/lesson_drop/(?P<lesson_id>\d+)/$',
        'student.views.drop_lesson', name="lesson_drop"),

    #Student Experiment Related
    url(r'^student/submit_report/(?P<experiment_id>\d+)$',
        'student.views.submit_report',
        name="submit_report"),
    url(r'^student/experiment/(?P<experiment_id>\d+)/$',
        'student.views.experiment_information',
        name="student_experiment_info"),

    #Student Experiment Report Related
    url(r'^tecaher/experiment_report/(?P<experiment_report_id>\d+)/evaluate/$',
        'teacher.views.experiment_report_evaluate',
        name='experiment_report_evaluate'),

    #Teacher Related
    url(r'^teacher/$', 'teacher.views.index', name='teacher_index'),
    url(r'^teacher/dashboard/$', 'teacher.views.dashboard',
        name='teacher_dashboard'),
    url(r'^teacher/signin/$', 'teacher.views.sign_in',
        name='teacher_signin'),
    url(r'^teacher/signout/$', 'teacher.views.sign_out',
        name='teacher_signout'),
    url(r'^teacher/profile/$', 'teacher.views.teacher_profile',
        name='teacher_profile'),

    #Teacher Lesson Category Related
    url(r'^teacher/category/create/$',
        'experiment.views.create_lesson_category',
        name='create_lesson_category'),
    url(r'^teacher/category/list/$',
        'experiment.views.lesson_category_list', name="category_list"),

    #Teacher Lesson Related
    url(r'^teacher/lesson/create/$', 'experiment.views.create_lesson',
        name='create_lesson'),
    url(r'^teacher/lesson/(?P<lesson_id>\d+)/$',
        'experiment.views.lesson_information', name="lesson_info"),
    url(r'^teacher/update_lesson/(?P<lesson_id>\d+)/$',
        'experiment.views.update_lesson', name='update_lesson'),
    url(r'^teacher/lesson/(?P<lesson_id>\d+)/delete/$',
        'experiment.views.delete_lesson', name='delete_lesson'),
    url(r'^teacher/lesson_list/$', 'experiment.views.lesson_list_all',
        name="teacher_lesson_list_all"),
    url(r'^teacher/lesson_list/(?P<category_id>\d+)/$',
        'experiment.views.lesson_list', name="teacher_lesson_list"),

    #Teacher Experiment Related
    url(r'^teacher/create_experiment/(?P<lesson_id>\d+)/$',
        'experiment.views.create_experiment', name="create_experiment"),
    url(r'^teacher/experiment/(?P<experiment_id>\d+)/$',
        'experiment.views.experiment_information', name="experiment_info"),
    url(r'^teacher/experiment/(?P<experiment_id>\d+)/delete/$',
        'experiment.views.delete_experiment', name='delete_experiment'),

    #Teacher Experiment Report Related
    url(r'^teacher/experiment/(?P<experiment_id>\d+)/modify/$',
        'experiment.views.experiment_modify', name='experiment_modify'),

)
<|endoftext|>


<commit_before>"""Utility functions available for use by Controllers

``etag_cache``, ``redirect_to``, and ``abort``.
"""
import logging
import warnings

import paste.httpexceptions as httpexceptions
from routes import url_for
from webob import Request as WebObRequest
from webob import Response as WebObResponse
from webob.exc import status_map

import pylons
import pylons.legacy

__all__ = ['abort', 'etag_cache', 'redirect_to', 'Request', 'Response']

log = logging.getLogger(__name__)

class Request(WebObRequest):
    charset = 'utf-8'
    unicode_errors = 'replace'
    language = 'en-us'

    def determine_browser_charset(self):
        return self.accept_charset

    def languages(self):
        return self.accept_language.best_matches(self.language)
    languages = property(languages)

    def match_accept(self, mimetypes):
        return self.accept.first_match(mimetypes)

class Response(WebObResponse):
    default_content_type = 'text/html'
    errors = 'strict'
    content = WebObResponse.body

    def determine_charset(self):
        return self.charset

    def has_header(self, header):
        return header in self.headers

    def get_content(self):
        return self.body

    def write(self, content):
        self.body_file.write(content)

    def wsgi_response(self):
        return self.status, self.headers, self.body

def etag_cache(key=None):
    """Use the HTTP Entity Tag cache for Browser side caching

    If a "If-None-Match" header is found, and equivilant to ``key``, then
    a ``304`` HTTP message will be returned with the ETag to tell the browser
    that it should use its current cache of the page.

    Otherwise, the ETag header will be added to the response headers.

    Suggested use is within a Controller Action like so:

    .. code-block:: Python

        import pylons

        class YourController(BaseController):
            def index(self):
                etag_cache(key=1)
                return render('/splash.mako')

    .. Note::
        This works because etag_cache will raise an HTTPNotModified
        exception if the ETag recieved matches the key provided.
    """
    if_none_match = pylons.request.environ.get('HTTP_IF_NONE_MATCH', None)
    pylons.response.headers['ETag'] = key
    if str(key) == if_none_match:
        log.debug("ETag match, returning 304 HTTP Not Modified Response")
        pylons.response.headers.pop('Content-Type', None)
        pylons.response.headers.pop('Cache-Control', None)
        pylons.response.headers.pop('Pragma', None)
        raise status_map[304]()
    else:
        log.debug("ETag didn't match, returning response object")
        return pylons.response

def abort(status_code=None, detail="", headers=None, comment=None):
    """Aborts the request immediately by returning an HTTP exception

    In the event that the status_code is a 300 series error, the detail
    attribute will be used as the Location header should one not be specified
    in the headers attribute.
    """
    exc = status_map[status_code](detail=detail, headers=headers,
                                  comment=comment)
    log.debug("Aborting request, status: %s, detail: %r, headers: %r, "
              "comment: %r", status_code, detail, headers, comment)
    raise exc

def redirect_to(*args, **kargs):
    """Raises a redirect exception

    Optionally, a _code variable may be passed with the status code of the
    redirect, ie:

    .. code-block:: Python

        redirect_to('home_page', _code=303)

    """
    response = kargs.pop('_response', None)
    status_code = kargs.pop('_code', 302)
    exc = status_map[status_code]
    found = exc(location=url_for(*args, **kargs))
    log.debug("Generating %s redirect" % status_code)
    raise found
<commit_msg>Adding docs for WebOb subclasses.<commit_after>"""Utility functions available for use by Controllers

``etag_cache``, ``redirect_to``, and ``abort``.
"""
import logging
import warnings

import paste.httpexceptions as httpexceptions
from routes import url_for
from webob import Request as WebObRequest
from webob import Response as WebObResponse
from webob.exc import status_map

import pylons
import pylons.legacy

__all__ = ['abort', 'etag_cache', 'redirect_to', 'Request', 'Response']

log = logging.getLogger(__name__)

class Request(WebObRequest):
    """WebOb Request subclass

    The WebOb Request has no charset, or other defaults. This subclass
    adds defaults, along with several methods for backwards
    compatibility with paste.wsgiwrappers.WSGIRequest.

    """
    charset = 'utf-8'
    unicode_errors = 'replace'
    language = 'en-us'

    def determine_browser_charset(self):
        return self.accept_charset

    def languages(self):
        return self.accept_language.best_matches(self.language)
    languages = property(languages)

    def match_accept(self, mimetypes):
        return self.accept.first_match(mimetypes)

class Response(WebObResponse):
    """WebOb Response subclass

    The WebOb Response has no default content type, or error defaults.
    This subclass adds defaults, along with several methods for
    backwards compatibility with paste.wsgiwrappers.WSGIResponse.

    """
    default_content_type = 'text/html'
    errors = 'strict'
    content = WebObResponse.body

    def determine_charset(self):
        return self.charset

    def has_header(self, header):
        return header in self.headers

    def get_content(self):
        return self.body

    def write(self, content):
        self.body_file.write(content)

    def wsgi_response(self):
        return self.status, self.headers, self.body

def etag_cache(key=None):
    """Use the HTTP Entity Tag cache for Browser side caching

    If a "If-None-Match" header is found, and equivilant to ``key``, then
    a ``304`` HTTP message will be returned with the ETag to tell the browser
    that it should use its current cache of the page.

    Otherwise, the ETag header will be added to the response headers.

    Suggested use is within a Controller Action like so:

    .. code-block:: Python

        import pylons

        class YourController(BaseController):
            def index(self):
                etag_cache(key=1)
                return render('/splash.mako')

    .. Note::
        This works because etag_cache will raise an HTTPNotModified
        exception if the ETag recieved matches the key provided.
    """
    if_none_match = pylons.request.environ.get('HTTP_IF_NONE_MATCH', None)
    pylons.response.headers['ETag'] = key
    if str(key) == if_none_match:
        log.debug("ETag match, returning 304 HTTP Not Modified Response")
        pylons.response.headers.pop('Content-Type', None)
        pylons.response.headers.pop('Cache-Control', None)
        pylons.response.headers.pop('Pragma', None)
        raise status_map[304]()
    else:
        log.debug("ETag didn't match, returning response object")
        return pylons.response

def abort(status_code=None, detail="", headers=None, comment=None):
    """Aborts the request immediately by returning an HTTP exception

    In the event that the status_code is a 300 series error, the detail
    attribute will be used as the Location header should one not be specified
    in the headers attribute.
    """
    exc = status_map[status_code](detail=detail, headers=headers,
                                  comment=comment)
    log.debug("Aborting request, status: %s, detail: %r, headers: %r, "
              "comment: %r", status_code, detail, headers, comment)
    raise exc

def redirect_to(*args, **kargs):
    """Raises a redirect exception

    Optionally, a _code variable may be passed with the status code of the
    redirect, ie:

    .. code-block:: Python

        redirect_to('home_page', _code=303)

    """
    response = kargs.pop('_response', None)
    status_code = kargs.pop('_code', 302)
    exc = status_map[status_code]
    found = exc(location=url_for(*args, **kargs))
    log.debug("Generating %s redirect" % status_code)
    raise found
<|endoftext|>


<commit_before>import cgi

from google.appengine.api import users
from google.appengine.ext import webapp
from google.appengine.ext.webapp.util import run_wsgi_app
from google.appengine.ext import db

class Greeting(db.Model):
  author = db.UserProperty()
  content = db.StringProperty(multiline=True)
  date = db.DateTimeProperty(auto_now_add=True)

class MainPage(webapp.RequestHandler):
  def get(self):
    self.response.out.write('')

    greetings = db.GqlQuery("SELECT * FROM Greeting ORDER BY date DESC LIMIT 10")

    for greeting in greetings:
      if greeting.author:
        self.response.out.write('%s wrote:' % greeting.author.nickname())
      else:
        self.response.out.write('An anonymous person wrote:')
      self.response.out.write('
%s
' %
                              cgi.escape(greeting.content))

    # Write the submission form and the footer of the page
    self.response.out.write("""
          <form action="/sign" method="post">

<textarea name="content" rows="3" cols="60"></textarea>

<input type="submit" value="Sign Guestbook">

          </form>

      """)

class Guestbook(webapp.RequestHandler):
  def post(self):
    greeting = Greeting()

    if users.get_current_user():
      greeting.author = users.get_current_user()

    greeting.content = self.request.get('content')
    greeting.put()
    self.redirect('/')

application = webapp.WSGIApplication(
                                     [('/', MainPage),
                                      ('/sign', Guestbook)],
                                     debug=True)

def main():
  run_wsgi_app(application)

if __name__ == "__main__":
  main()
<commit_msg> Removed old file<commit_after><|endoftext|>


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

import mock
import requests
import requests_unixsocket

from pylxd import client, exceptions
from pylxd.tests.testing import requires_ws4py

class TestClient(unittest.TestCase):
    """Tests for pylxd.client.Client."""

    def setUp(self):
        self.get_patcher = mock.patch('pylxd.client._APINode.get')
        self.get = self.get_patcher.start()

        self.post_patcher = mock.patch('pylxd.client._APINode.post')
        self.post = self.post_patcher.start()

        response = mock.MagicMock(status_code=200)
        response.json.return_value = {'metadata': {
            'auth': 'trusted',
            'environment': {'storage': 'zfs'},
        }}
        self.get.return_value = response

        post_response = mock.MagicMock(status_code=200)
        self.post.return_value = post_response

    def tearDown(self):
        self.get_patcher.stop()
        self.post_patcher.stop()

    @mock.patch('os.path.exists')
    def test_create(self, _path_exists):
        """Client creation sets default API endpoint."""
        _path_exists.return_value = False
        expected = 'http+unix://%2Fvar%2Flib%2Flxd%2Funix.socket/1.0'

        an_client = client.Client()

        self.assertEqual(expected, an_client.api._api_endpoint)

    @mock.patch('os.path.exists')
    @mock.patch('os.environ')
    def test_create_with_snap_lxd(self, _environ, _path_exists):
        # """Client creation sets default API endpoint."""
        _path_exists.return_value = True
        expected = ('http+unix://%2Fvar%2Fsnap%2Flxd%2F'
                    'common%2Flxd%2Funix.socket/1.0')

        an_client = client.Client()
        print("path exists: {}".format(os.path.exists('stuff')))
        print("env: {}".format(os.environ))
        self.assertEqual(expected, an_client.api._api_endpoint)

    def test_create_LXD_DIR(self):
        """When LXD_DIR is set, use it in the client."""
        os.environ['LXD_DIR'] = '/lxd'
        expected = 'http+unix://%2Flxd%2Funix.socket/1.0'

        an_client = client.Client()

        self.assertEqual(expected, an_client.api._api_endpoint)

    def test_create_endpoint(self):
        """Explicitly set the client endpoint."""
        endpoint = 'http://lxd'
        expected = 'http://lxd/1.0'

        an_client = client.Client(endpoint=endpoint)

        self.assertEqual(expected, an_client.api._api_endpoint)

    def test_create_endpoint_unixsocket(self):
        """Test with unix socket endpoint."""
        endpoint = '/tmp/unix.socket'
        expected = 'http+unix://%2Ftmp%2Funix.socket/1.0'

        real_isfile = os.path.isfile
        os.path.isfile = lambda x: True
        an_client = client.Client(endpoint)
        os.path.isfile = real_isfile

        self.assertEqual(expected, an_client.api._api_endpoint)

    def test_connection_404(self):
        """If the endpoint 404s, an exception is raised."""
        response = mock.MagicMock(status_code=404)
        self.get.return_value = response

        self.assertRaises(exceptions.ClientConnectionFailed, client.Client)

    def test_connection_failed(self):
        """If the connection fails, an exception is raised."""
        def raise_exception():
            raise requests.exceptions.ConnectionError()
        self.get.side_effect = raise_exception
        self.get.return_value = None

        self.assertRaises(exceptions.ClientConnectionFailed, client.Client)

    def test_connection_untrusted(self):
        """Client.trusted is False when certs are untrusted."""
        response = mock.MagicMock(status_code=200)
        response.json.return_value = {'metadata': {'auth': 'untrusted'}}
        self.get.return_value = response

        an_client = client.Client()

        self.assertFalse(an_client.trusted)

    def test_connection_trusted(self):
        """Client.trusted is True when certs are untrusted."""
        response = mock.MagicMock(status_code=200)
        response.json.return_value = {'metadata': {'auth': 'trusted'}}
        self.get.return_value = response

        an_client = client.Client()

        self.assertTrue(an_client.trusted)

    def test_authenticate(self):
        """A client is authenticated."""
        response = mock.MagicMock(status_code=200)
        response.json.return_value = {'metadata': {'auth': 'untrusted'}}
        self.get.return_value = response

        certs = (
            os.path.join(os.path.dirname(__file__), 'lxd.crt'),
            os.path.join(os.path.dirname(__file__), 'lxd.key'))
        an_client = client.Client('https://lxd', cert=certs)

        get_count = []

        def _get(*args, **kwargs):
            if len(get_count) == 0:
                get_count.append(None)
                return {'metadata': {
                    'type': 'client',
                    'fingerprint': 'eaf55b72fc23aa516d709271df9b0116064bf8cfa009cf34c67c33ad32c2320c',  # NOQA
                }}
            else:
                return {'metadata': {'auth': 'trusted'}}
        response = mock.MagicMock(status_code=200)
        response.json.side_effect = _get
        self.get.return_value = response

        an_client.authenticate('test-password')

        self.assertTrue(an_client.trusted)

    def test_authenticate_already_authenticated(self):
        """If the client is already authenticated, nothing happens."""
        an_client = client.Client()

        an_client.authenticate('test-password')

        self.assertTrue(an_client.trusted)

    def test_host_info(self):
        """Perform a host query."""
        an_client = client.Client()
        self.assertEqual('zfs', an_client.host_info['environment']['storage'])

    @requires_ws4py
    def test_events(self):
        """The default websocket client is returned."""
        an_client = client.Client()

        ws_client = an_client.events()

        self.assertEqual('/1.0/events', ws_client.resource)

    def test_events_no_ws4py(self):
        """No ws4py will result in a ValueError."""
        from pylxd import client
        old_installed = client._ws4py_installed
        client._ws4py_installed = False

        def cleanup():
            client._ws4py_installed = old_installed
        self.addCleanup(cleanup)

        an_client = client.Client()

        self.assertRaises(ValueError, an_client.events)
        client._ws4py_installed

    @requires_ws4py
    def test_events_unix_socket(self):
        """A unix socket compatible websocket client is returned."""
        websocket_client = mock.Mock(resource=None)
        WebsocketClient = mock.Mock()
        WebsocketClient.return_value = websocket_client
        os.environ['LXD_DIR'] = '/lxd'
        an_client = client.Client()

        an_client.events(websocket_client=WebsocketClient)

        WebsocketClient.assert_called_once_with('ws+unix:///lxd/unix.socket')

    @requires_ws4py
    def test_events_htt(self):
        """An http compatible websocket client is returned."""
        websocket_client = mock.Mock(resource=None)
        WebsocketClient = mock.Mock()
        WebsocketClient.return_value = websocket_client
        an_client = client.Client('http://lxd.local')

        an_client.events(websocket_client=WebsocketClient)

        WebsocketClient.assert_called_once_with('ws://lxd.local')

    @requires_ws4py
    def test_events_https(self):
        """An https compatible websocket client is returned."""
        websocket_client = mock.Mock(resource=None)
        WebsocketClient = mock.Mock()
        WebsocketClient.return_value = websocket_client
        an_client = client.Client('https://lxd.local')

        an_client.events(websocket_client=WebsocketClient)

        WebsocketClient.assert_called_once_with('wss://lxd.local')

class TestAPINode(unittest.TestCase):
    """Tests for pylxd.client._APINode."""

    def test_getattr(self):
        """API Nodes can use object notation for nesting."""
        node = client._APINode('http://test.com')

        new_node = node.test

        self.assertEqual(
            'http://test.com/test', new_node._api_endpoint)

    def test_getitem(self):
        """API Nodes can use dict notation for nesting."""
        node = client._APINode('http://test.com')

        new_node = node['test']

        self.assertEqual(
            'http://test.com/test', new_node._api_endpoint)

    def test_session_http(self):
        """HTTP nodes return the default requests session."""
        node = client._APINode('http://test.com')

        self.assertIsInstance(node.session, requests.Session)

    def test_session_unix_socket(self):
        """HTTP nodes return a requests_unixsocket session."""
        node = client._APINode('http+unix://test.com')

        self.assertIsInstance(node.session, requests_unixsocket.Session)

    @mock.patch('pylxd.client.requests.Session')
    def test_get(self, Session):
        """Perform a session get."""
        response = mock.Mock(**{
            'status_code': 200,
            'json.return_value': {'type': 'sync'},
        })
        session = mock.Mock(**{'get.return_value': response})
        Session.return_value = session

        node = client._APINode('http://test.com')

        node.get()

        session.get.assert_called_once_with('http://test.com', timeout=None)

    @mock.patch('pylxd.client.requests.Session')
    def test_post(self, Session):
        """Perform a session post."""
        response = mock.Mock(**{
            'status_code': 200,
            'json.return_value': {'type': 'sync'},
        })
        session = mock.Mock(**{'post.return_value': response})
        Session.return_value = session

        node = client._APINode('http://test.com')

        node.post()

        session.post.assert_called_once_with('http://test.com', timeout=None)

    @mock.patch('pylxd.client.requests.Session')
    def test_post_200_not_sync(self, Session):
        """A status code of 200 with async request raises an exception."""
        response = mock.Mock(**{
            'status_code': 200,
            'json.return_value': {'type': 'async'},
        })
        session = mock.Mock(**{'post.return_value': response})
        Session.return_value = session

        node = client._APINode('http://test.com')

        self.assertRaises(
            exceptions.LXDAPIException,
            node.post)

    @mock.patch('pylxd.client.requests.Session')
    def test_post_missing_type_200(self, Session):
        """A missing response type raises an exception."""
        response = mock.Mock(**{
            'status_code': 200,
            'json.return_value': {},
        })
        session = mock.Mock(**{'post.return_value': response})
        Session.return_value = session

        node = client._APINode('http://test.com')

        self.assertRaises(
            exceptions.LXDAPIException,
            node.post)

    @mock.patch('pylxd.client.requests.Session')
    def test_put(self, Session):
        """Perform a session put."""
        response = mock.Mock(**{
            'status_code': 200,
            'json.return_value': {'type': 'sync'},
        })
        session = mock.Mock(**{'put.return_value': response})
        Session.return_value = session

        node = client._APINode('http://test.com')

        node.put()

        session.put.assert_called_once_with('http://test.com', timeout=None)

    @mock.patch('pylxd.client.requests.Session')
    def test_delete(self, Session):
        """Perform a session delete."""
        response = mock.Mock(**{
            'status_code': 200,
            'json.return_value': {'type': 'sync'},
        })
        session = mock.Mock(**{'delete.return_value': response})
        Session.return_value = session

        node = client._APINode('http://test.com')

        node.delete()

        session.delete.assert_called_once_with('http://test.com', timeout=None)

class TestWebsocketClient(unittest.TestCase):
    """Tests for pylxd.client.WebsocketClient."""

    @requires_ws4py
    def test_handshake_ok(self):
        """A `message` attribute of an empty list is created."""
        ws_client = client._WebsocketClient('ws://an/fake/path')

        ws_client.handshake_ok()

        self.assertEqual([], ws_client.messages)

    @requires_ws4py
    def test_received_message(self):
        """A json dict is added to the messages attribute."""
        message = mock.Mock(data=json.dumps({'test': 'data'}).encode('utf-8'))
        ws_client = client._WebsocketClient('ws://an/fake/path')
        ws_client.handshake_ok()

        ws_client.received_message(message)

        self.assertEqual({'test': 'data'}, ws_client.messages[0])
<commit_msg>remove prints<commit_after># Copyright (c) 2016 Canonical Ltd
#
#    Licensed under the Apache License, Version 2.0 (the "License"); you may
#    not use this file except in compliance with the License. You may obtain
#    a copy of the License at
#
#         http://www.apache.org/licenses/LICENSE-2.0
#
#    Unless required by applicable law or agreed to in writing, software
#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
#    License for the specific language governing permissions and limitations
#    under the License.
import json
import os
import os.path
import unittest

import mock
import requests
import requests_unixsocket

from pylxd import client, exceptions
from pylxd.tests.testing import requires_ws4py

class TestClient(unittest.TestCase):
    """Tests for pylxd.client.Client."""

    def setUp(self):
        self.get_patcher = mock.patch('pylxd.client._APINode.get')
        self.get = self.get_patcher.start()

        self.post_patcher = mock.patch('pylxd.client._APINode.post')
        self.post = self.post_patcher.start()

        response = mock.MagicMock(status_code=200)
        response.json.return_value = {'metadata': {
            'auth': 'trusted',
            'environment': {'storage': 'zfs'},
        }}
        self.get.return_value = response

        post_response = mock.MagicMock(status_code=200)
        self.post.return_value = post_response

    def tearDown(self):
        self.get_patcher.stop()
        self.post_patcher.stop()

    @mock.patch('os.path.exists')
    def test_create(self, _path_exists):
        """Client creation sets default API endpoint."""
        _path_exists.return_value = False
        expected = 'http+unix://%2Fvar%2Flib%2Flxd%2Funix.socket/1.0'

        an_client = client.Client()

        self.assertEqual(expected, an_client.api._api_endpoint)

    @mock.patch('os.path.exists')
    @mock.patch('os.environ')
    def test_create_with_snap_lxd(self, _environ, _path_exists):
        # """Client creation sets default API endpoint."""
        _path_exists.return_value = True
        expected = ('http+unix://%2Fvar%2Fsnap%2Flxd%2F'
                    'common%2Flxd%2Funix.socket/1.0')

        an_client = client.Client()
        self.assertEqual(expected, an_client.api._api_endpoint)

    def test_create_LXD_DIR(self):
        """When LXD_DIR is set, use it in the client."""
        os.environ['LXD_DIR'] = '/lxd'
        expected = 'http+unix://%2Flxd%2Funix.socket/1.0'

        an_client = client.Client()

        self.assertEqual(expected, an_client.api._api_endpoint)

    def test_create_endpoint(self):
        """Explicitly set the client endpoint."""
        endpoint = 'http://lxd'
        expected = 'http://lxd/1.0'

        an_client = client.Client(endpoint=endpoint)

        self.assertEqual(expected, an_client.api._api_endpoint)

    def test_create_endpoint_unixsocket(self):
        """Test with unix socket endpoint."""
        endpoint = '/tmp/unix.socket'
        expected = 'http+unix://%2Ftmp%2Funix.socket/1.0'

        real_isfile = os.path.isfile
        os.path.isfile = lambda x: True
        an_client = client.Client(endpoint)
        os.path.isfile = real_isfile

        self.assertEqual(expected, an_client.api._api_endpoint)

    def test_connection_404(self):
        """If the endpoint 404s, an exception is raised."""
        response = mock.MagicMock(status_code=404)
        self.get.return_value = response

        self.assertRaises(exceptions.ClientConnectionFailed, client.Client)

    def test_connection_failed(self):
        """If the connection fails, an exception is raised."""
        def raise_exception():
            raise requests.exceptions.ConnectionError()
        self.get.side_effect = raise_exception
        self.get.return_value = None

        self.assertRaises(exceptions.ClientConnectionFailed, client.Client)

    def test_connection_untrusted(self):
        """Client.trusted is False when certs are untrusted."""
        response = mock.MagicMock(status_code=200)
        response.json.return_value = {'metadata': {'auth': 'untrusted'}}
        self.get.return_value = response

        an_client = client.Client()

        self.assertFalse(an_client.trusted)

    def test_connection_trusted(self):
        """Client.trusted is True when certs are untrusted."""
        response = mock.MagicMock(status_code=200)
        response.json.return_value = {'metadata': {'auth': 'trusted'}}
        self.get.return_value = response

        an_client = client.Client()

        self.assertTrue(an_client.trusted)

    def test_authenticate(self):
        """A client is authenticated."""
        response = mock.MagicMock(status_code=200)
        response.json.return_value = {'metadata': {'auth': 'untrusted'}}
        self.get.return_value = response

        certs = (
            os.path.join(os.path.dirname(__file__), 'lxd.crt'),
            os.path.join(os.path.dirname(__file__), 'lxd.key'))
        an_client = client.Client('https://lxd', cert=certs)

        get_count = []

        def _get(*args, **kwargs):
            if len(get_count) == 0:
                get_count.append(None)
                return {'metadata': {
                    'type': 'client',
                    'fingerprint': 'eaf55b72fc23aa516d709271df9b0116064bf8cfa009cf34c67c33ad32c2320c',  # NOQA
                }}
            else:
                return {'metadata': {'auth': 'trusted'}}
        response = mock.MagicMock(status_code=200)
        response.json.side_effect = _get
        self.get.return_value = response

        an_client.authenticate('test-password')

        self.assertTrue(an_client.trusted)

    def test_authenticate_already_authenticated(self):
        """If the client is already authenticated, nothing happens."""
        an_client = client.Client()

        an_client.authenticate('test-password')

        self.assertTrue(an_client.trusted)

    def test_host_info(self):
        """Perform a host query."""
        an_client = client.Client()
        self.assertEqual('zfs', an_client.host_info['environment']['storage'])

    @requires_ws4py
    def test_events(self):
        """The default websocket client is returned."""
        an_client = client.Client()

        ws_client = an_client.events()

        self.assertEqual('/1.0/events', ws_client.resource)

    def test_events_no_ws4py(self):
        """No ws4py will result in a ValueError."""
        from pylxd import client
        old_installed = client._ws4py_installed
        client._ws4py_installed = False

        def cleanup():
            client._ws4py_installed = old_installed
        self.addCleanup(cleanup)

        an_client = client.Client()

        self.assertRaises(ValueError, an_client.events)
        client._ws4py_installed

    @requires_ws4py
    def test_events_unix_socket(self):
        """A unix socket compatible websocket client is returned."""
        websocket_client = mock.Mock(resource=None)
        WebsocketClient = mock.Mock()
        WebsocketClient.return_value = websocket_client
        os.environ['LXD_DIR'] = '/lxd'
        an_client = client.Client()

        an_client.events(websocket_client=WebsocketClient)

        WebsocketClient.assert_called_once_with('ws+unix:///lxd/unix.socket')

    @requires_ws4py
    def test_events_htt(self):
        """An http compatible websocket client is returned."""
        websocket_client = mock.Mock(resource=None)
        WebsocketClient = mock.Mock()
        WebsocketClient.return_value = websocket_client
        an_client = client.Client('http://lxd.local')

        an_client.events(websocket_client=WebsocketClient)

        WebsocketClient.assert_called_once_with('ws://lxd.local')

    @requires_ws4py
    def test_events_https(self):
        """An https compatible websocket client is returned."""
        websocket_client = mock.Mock(resource=None)
        WebsocketClient = mock.Mock()
        WebsocketClient.return_value = websocket_client
        an_client = client.Client('https://lxd.local')

        an_client.events(websocket_client=WebsocketClient)

        WebsocketClient.assert_called_once_with('wss://lxd.local')

class TestAPINode(unittest.TestCase):
    """Tests for pylxd.client._APINode."""

    def test_getattr(self):
        """API Nodes can use object notation for nesting."""
        node = client._APINode('http://test.com')

        new_node = node.test

        self.assertEqual(
            'http://test.com/test', new_node._api_endpoint)

    def test_getitem(self):
        """API Nodes can use dict notation for nesting."""
        node = client._APINode('http://test.com')

        new_node = node['test']

        self.assertEqual(
            'http://test.com/test', new_node._api_endpoint)

    def test_session_http(self):
        """HTTP nodes return the default requests session."""
        node = client._APINode('http://test.com')

        self.assertIsInstance(node.session, requests.Session)

    def test_session_unix_socket(self):
        """HTTP nodes return a requests_unixsocket session."""
        node = client._APINode('http+unix://test.com')

        self.assertIsInstance(node.session, requests_unixsocket.Session)

    @mock.patch('pylxd.client.requests.Session')
    def test_get(self, Session):
        """Perform a session get."""
        response = mock.Mock(**{
            'status_code': 200,
            'json.return_value': {'type': 'sync'},
        })
        session = mock.Mock(**{'get.return_value': response})
        Session.return_value = session

        node = client._APINode('http://test.com')

        node.get()

        session.get.assert_called_once_with('http://test.com', timeout=None)

    @mock.patch('pylxd.client.requests.Session')
    def test_post(self, Session):
        """Perform a session post."""
        response = mock.Mock(**{
            'status_code': 200,
            'json.return_value': {'type': 'sync'},
        })
        session = mock.Mock(**{'post.return_value': response})
        Session.return_value = session

        node = client._APINode('http://test.com')

        node.post()

        session.post.assert_called_once_with('http://test.com', timeout=None)

    @mock.patch('pylxd.client.requests.Session')
    def test_post_200_not_sync(self, Session):
        """A status code of 200 with async request raises an exception."""
        response = mock.Mock(**{
            'status_code': 200,
            'json.return_value': {'type': 'async'},
        })
        session = mock.Mock(**{'post.return_value': response})
        Session.return_value = session

        node = client._APINode('http://test.com')

        self.assertRaises(
            exceptions.LXDAPIException,
            node.post)

    @mock.patch('pylxd.client.requests.Session')
    def test_post_missing_type_200(self, Session):
        """A missing response type raises an exception."""
        response = mock.Mock(**{
            'status_code': 200,
            'json.return_value': {},
        })
        session = mock.Mock(**{'post.return_value': response})
        Session.return_value = session

        node = client._APINode('http://test.com')

        self.assertRaises(
            exceptions.LXDAPIException,
            node.post)

    @mock.patch('pylxd.client.requests.Session')
    def test_put(self, Session):
        """Perform a session put."""
        response = mock.Mock(**{
            'status_code': 200,
            'json.return_value': {'type': 'sync'},
        })
        session = mock.Mock(**{'put.return_value': response})
        Session.return_value = session

        node = client._APINode('http://test.com')

        node.put()

        session.put.assert_called_once_with('http://test.com', timeout=None)

    @mock.patch('pylxd.client.requests.Session')
    def test_delete(self, Session):
        """Perform a session delete."""
        response = mock.Mock(**{
            'status_code': 200,
            'json.return_value': {'type': 'sync'},
        })
        session = mock.Mock(**{'delete.return_value': response})
        Session.return_value = session

        node = client._APINode('http://test.com')

        node.delete()

        session.delete.assert_called_once_with('http://test.com', timeout=None)

class TestWebsocketClient(unittest.TestCase):
    """Tests for pylxd.client.WebsocketClient."""

    @requires_ws4py
    def test_handshake_ok(self):
        """A `message` attribute of an empty list is created."""
        ws_client = client._WebsocketClient('ws://an/fake/path')

        ws_client.handshake_ok()

        self.assertEqual([], ws_client.messages)

    @requires_ws4py
    def test_received_message(self):
        """A json dict is added to the messages attribute."""
        message = mock.Mock(data=json.dumps({'test': 'data'}).encode('utf-8'))
        ws_client = client._WebsocketClient('ws://an/fake/path')
        ws_client.handshake_ok()

        ws_client.received_message(message)

        self.assertEqual({'test': 'data'}, ws_client.messages[0])
<|endoftext|>