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

from __future__ import (division as _, print_function as _,
                absolute_import as _, unicode_literals as _)

# Version number
__version__ = "1.0"

# Was coronagraph imported from setup.py?
try:
    __CORONAGRAPH_SETUP__
except NameError:
    __CORONAGRAPH_SETUP__ = False

if not __CORONAGRAPH_SETUP__:
    # This is a regular coronagraph run
    from .teleplanstar import *
    from . import observe
    from .observe import *
    from .degrade_spec import *
    from . import imager
    from .convolve_spec import *
    from .count_rates import *
    from .count_rates_wrapper import *
    from . import noise_routines
    from .transits import *
<commit_msg>bummed version to 1.01<commit_after>#!/usr/bin/env python
# -*- coding: utf-8 -*-

from __future__ import (division as _, print_function as _,
                absolute_import as _, unicode_literals as _)

# Version number
__version__ = "1.01"

# Was coronagraph imported from setup.py?
try:
    __CORONAGRAPH_SETUP__
except NameError:
    __CORONAGRAPH_SETUP__ = False

if not __CORONAGRAPH_SETUP__:
    # This is a regular coronagraph run
    from .teleplanstar import *
    from . import observe
    from .observe import *
    from .degrade_spec import *
    from . import imager
    from .convolve_spec import *
    from .count_rates import *
    from .count_rates_wrapper import *
    from . import noise_routines
    from .transits import *
<|endoftext|>


<commit_before>import json
import warnings
import h5py
import numpy as np
from .. import options
from ..database import db
from .braindata import BrainData, VolumeData, VertexData, _hash

default_cmap = options.config.get("basic", "default_cmap")

def normalize(data):
    if isinstance(data, tuple):
        if len(data) == 3:
            if data[0].dtype == np.uint8:
                return VolumeRGB(data[0][...,0], data[0][...,1], data[0][...,2], *data[1:])
            return Volume(*data)
        elif len(data) == 2:
            return Vertex(*data)
        else:
            raise TypeError("Invalid input for Dataview")
    elif isinstance(data, Dataview):
        return data
    else:
        raise TypeError("Invalid input for Dataview")

def _from_hdf_data(h5, name, xfmname=None, **kwargs):
    """Decodes a __hash named node from an HDF file into the
    constituent Vertex or Volume object"""
    dnode = h5.get("/data/%s"%name)
    if dnode is None:
        dnode = h5.get(name)

    subj = dnode.attrs['subject']
    #support old style xfmname saving as attribute
    if xfmname is None and 'xfmname' in dnode.attrs:
        xfmname = dnode.attrs['xfmname']

    mask = None
    if "mask" in dnode.attrs:
        if dnode.attrs['mask'].startswith("__"):
            mask = h5['/subjects/%s/transforms/%s/masks/%s'%(dnode.attrs['subject'], xfmname, dnode.attrs['mask'])].value
        else:
            mask = dnode.attrs['mask']

    #support old style RGB volumes
    if dnode.dtype == np.uint8 and dnode.shape[-1] in (3, 4):
        alpha = None
        if dnode.shape[-1] == 4:
            alpha = dnode[..., 3]

        if xfmname is None:
            return VertexRGB(dnode[...,0], dnode[...,1], dnode[...,2], subj,
                alpha=alpha, **kwargs)

        return VolumeRGB(dnode[...,0], dnode[...,1], dnode[...,2], subj, xfmname,
            alpha=alpha, mask=mask, **kwargs)

    if xfmname is None:
        return Vertex(dnode, subj, **kwargs)

    return Volume(dnode, subj, xfmname, mask=mask, **kwargs)

def _from_hdf_view(h5, data, xfmname=None, vmin=None, vmax=None,  **kwargs):
    try:
        basestring
        strcls = (unicode, str)
    except NameError:
        strcls = str

    if isinstance(data, strcls):
        return _from_hdf_data(h5, data, xfmname=xfmname, vmin=vmin, vmax=vmax, **kwargs)

    if len(data) == 2:
        dim1 = _from_hdf_data(h5, data[0], xfmname=xfmname[0])
        dim2 = _from_hdf_data(h5, data[1], xfmname=xfmname[1])
        cls = Vertex2D if isinstance(dim1, Vertex) else Volume2D
        return cls(dim1, dim2, vmin=vmin[0], vmin2=vmin[1],
            vmax=vmax[0], vmax2=vmax[1], **kwargs)
    elif len(data) == 4:
        red, green, blue = [_from_hdf_data(h5, d, xfmname=xfmname) for d in data[:3]]
        alpha = None
        if data[3] is not None:
            alpha = _from_hdf_data(h5, data[3], xfmname=xfmname)

        cls = VertexRGB if isinstance(red, Vertex) else VolumeRGB
        return cls(red, green, blue, alpha=alpha, **kwargs)
    else:
        raise ValueError("Invalid Dataview specification")

class Dataview(object):
    def __init__(self, cmap=None, vmin=None, vmax=None, description="", state=None, **kwargs):
        if self.__class__ == Dataview:
            raise TypeError('Cannot directly instantiate Dataview objects')

        self.cmap = cmap if cmap is not None else default_cmap
        self.vmin = vmin
        self.vmax = vmax
        self.state = state
        self.attrs = kwargs
        if 'priority' not in self.attrs:
            self.attrs['priority'] = 1
        self.description = description

    def copy(self, *args, **kwargs):
        kwargs.update(self.attrs)
        return self.__class__(*args,
            cmap=self.cmap,
            vmin=self.vmin,
            vmax=self.vmax,
            description=self.description,
            state=self.state,
            **kwargs)

    @property
    def priority(self):
        return self.attrs['priority']

    @priority.setter
    def priority(self, value):
        self.attrs['priority'] = value

    def to_json(self, simple=False):
        if simple:
            return dict()

        sdict = dict(
            state=self.state,
            attrs=self.attrs.copy(),
            desc=self.description)
        try:
            sdict.update(dict(
                cmap=[self.cmap],
                vmin=[self.vmin if self.vmin is not None else np.percentile(np.nan_to_num(self.data), 1)],
                vmax=[self.vmax if self.vmax is not None else np.percentile(np.nan_to_num(self.data), 99)]
                ))
        except AttributeError:
            pass
        return sdict

    @staticmethod
    def from_hdf(node):
        data = json.loads(node[0])
        desc = node[1]
        try:
            cmap = json.loads(node[2])
        except:
            cmap = node[2]
        vmin = json.loads(node[3])
        vmax = json.loads(node[4])
        state = json.loads(node[5])
        attrs = json.loads(node[6])
        try:
            xfmname = json.loads(node[7])
        except ValueError:
            xfmname = None

        if not isinstance(vmin, list):
            vmin = [vmin]
        if not isinstance(vmax, list):
            vmax = [vmax]
        if not isinstance(cmap, list):
            cmap = [cmap]

        if len(data) == 1:
            xfm = None if xfmname is None else xfmname[0]
            return _from_hdf_view(node.file, data[0], xfmname=xfm, cmap=cmap[0], description=desc,
                vmin=vmin[0], vmax=vmax[0], state=state, **attrs)
        else:
            views = [_from_hdf_view(node.file, d, xfmname=x) for d, x in zip(data, xfname)]
            raise NotImplementedError

    def _write_hdf(self, h5, name="data", data=None, xfmname=None):
        views = h5.require_group("/views")
        view = views.require_dataset(name, (8,), h5py.special_dtype(vlen=str))
        view[0] = json.dumps(data)
        view[1] = self.description
        try:
            view[2] = json.dumps([self.cmap])
            view[3] = json.dumps([self.vmin])
            view[4] = json.dumps([self.vmax])
        except AttributeError:
            #For VolumeRGB/Vertex, there is no cmap/vmin/vmax
            view[2] = None
            view[3:5] = "null"
        view[5] = json.dumps(self.state)
        view[6] = json.dumps(self.attrs)
        view[7] = json.dumps(xfmname)
        return view

    @property
    def raw(self):
        from matplotlib import colors, cm, pyplot as plt
        import glob, os
        # Get colormap from matplotlib or pycortex colormaps
        ## -- redundant code, here and in cortex/quicklflat.py -- ##
        if isinstance(self.cmap,(str,unicode)):
            if not self.cmap in cm.__dict__:
                # unknown colormap, test whether it's in pycortex colormaps
                cmapdir = options.config.get('webgl', 'colormaps')
                colormaps = glob.glob(os.path.join(cmapdir, "*.png"))
                colormaps = dict(((os.path.split(c)[1][:-4],c) for c in colormaps))
                if not self.cmap in colormaps:
                    raise Exception('Unkown color map!')
                I = plt.imread(colormaps[self.cmap])
                cmap = colors.ListedColormap(np.squeeze(I))
                # Register colormap while we're at it
                cm.register_cmap(self.cmap,cmap)
            else:
                cmap = self.cmap
        norm = colors.Normalize(self.vmin, self.vmax) # Does this do anything?
        return np.rollaxis(cmap(self.data), -1)

class Multiview(Dataview):
    def __init__(self, views, description=""):
        for view in views:
            if not isinstance(view, Dataview):
                raise TypeError("Must be a View object!")
        raise NotImplementedError
        self.views = views

    def uniques(self, collapse=False):
        for view in self.views:
            for sv in view.uniques(collapse=collapse):
                yield sv

class Volume(VolumeData, Dataview):
    def __init__(self, data, subject, xfmname, mask=None,
        cmap=None, vmin=None, vmax=None, description="", **kwargs):
        super(Volume, self).__init__(data, subject, xfmname, mask=mask,
            cmap=cmap, vmin=vmin, vmax=vmax, description=description, **kwargs)

    def _write_hdf(self, h5, name="data"):
        datanode = VolumeData._write_hdf(self, h5)
        viewnode = Dataview._write_hdf(self, h5, name=name,
            data=[self.name], xfmname=[self.xfmname])
        return viewnode

    @property
    def raw(self):
        r, g, b, a = super(Volume, self).raw
        return VolumeRGB(r, g, b, self.subject, self.xfmname, a,
            description=self.description, state=self.state, **self.attrs)

class Vertex(VertexData, Dataview):
    def __init__(self, data, subject, cmap=None, vmin=None, vmax=None, description="", **kwargs):
        super(Vertex, self).__init__(data, subject, cmap=cmap, vmin=vmin, vmax=vmax,
            description=description, **kwargs)

    def _write_hdf(self, h5, name="data"):
        datanode = VertexData._write_hdf(self, h5)
        viewnode = Dataview._write_hdf(self, h5, name=name, data=[self.name])
        return viewnode

    @property
    def raw(self):
        r, g, b, a = super(Vertex, self).raw
        return VertexRGB(r, g, b, self.subject, a,
            description=self.description, state=self.state, **self.attrs)

from .viewRGB import VolumeRGB, VertexRGB
from .view2D import Volume2D, Vertex2D
<commit_msg>Fixed minor bug w/ new colormap code<commit_after>import json
import warnings
import h5py
import numpy as np
from .. import options
from ..database import db
from .braindata import BrainData, VolumeData, VertexData, _hash

default_cmap = options.config.get("basic", "default_cmap")

def normalize(data):
    if isinstance(data, tuple):
        if len(data) == 3:
            if data[0].dtype == np.uint8:
                return VolumeRGB(data[0][...,0], data[0][...,1], data[0][...,2], *data[1:])
            return Volume(*data)
        elif len(data) == 2:
            return Vertex(*data)
        else:
            raise TypeError("Invalid input for Dataview")
    elif isinstance(data, Dataview):
        return data
    else:
        raise TypeError("Invalid input for Dataview")

def _from_hdf_data(h5, name, xfmname=None, **kwargs):
    """Decodes a __hash named node from an HDF file into the
    constituent Vertex or Volume object"""
    dnode = h5.get("/data/%s"%name)
    if dnode is None:
        dnode = h5.get(name)

    subj = dnode.attrs['subject']
    #support old style xfmname saving as attribute
    if xfmname is None and 'xfmname' in dnode.attrs:
        xfmname = dnode.attrs['xfmname']

    mask = None
    if "mask" in dnode.attrs:
        if dnode.attrs['mask'].startswith("__"):
            mask = h5['/subjects/%s/transforms/%s/masks/%s'%(dnode.attrs['subject'], xfmname, dnode.attrs['mask'])].value
        else:
            mask = dnode.attrs['mask']

    #support old style RGB volumes
    if dnode.dtype == np.uint8 and dnode.shape[-1] in (3, 4):
        alpha = None
        if dnode.shape[-1] == 4:
            alpha = dnode[..., 3]

        if xfmname is None:
            return VertexRGB(dnode[...,0], dnode[...,1], dnode[...,2], subj,
                alpha=alpha, **kwargs)

        return VolumeRGB(dnode[...,0], dnode[...,1], dnode[...,2], subj, xfmname,
            alpha=alpha, mask=mask, **kwargs)

    if xfmname is None:
        return Vertex(dnode, subj, **kwargs)

    return Volume(dnode, subj, xfmname, mask=mask, **kwargs)

def _from_hdf_view(h5, data, xfmname=None, vmin=None, vmax=None,  **kwargs):
    try:
        basestring
        strcls = (unicode, str)
    except NameError:
        strcls = str

    if isinstance(data, strcls):
        return _from_hdf_data(h5, data, xfmname=xfmname, vmin=vmin, vmax=vmax, **kwargs)

    if len(data) == 2:
        dim1 = _from_hdf_data(h5, data[0], xfmname=xfmname[0])
        dim2 = _from_hdf_data(h5, data[1], xfmname=xfmname[1])
        cls = Vertex2D if isinstance(dim1, Vertex) else Volume2D
        return cls(dim1, dim2, vmin=vmin[0], vmin2=vmin[1],
            vmax=vmax[0], vmax2=vmax[1], **kwargs)
    elif len(data) == 4:
        red, green, blue = [_from_hdf_data(h5, d, xfmname=xfmname) for d in data[:3]]
        alpha = None
        if data[3] is not None:
            alpha = _from_hdf_data(h5, data[3], xfmname=xfmname)

        cls = VertexRGB if isinstance(red, Vertex) else VolumeRGB
        return cls(red, green, blue, alpha=alpha, **kwargs)
    else:
        raise ValueError("Invalid Dataview specification")

class Dataview(object):
    def __init__(self, cmap=None, vmin=None, vmax=None, description="", state=None, **kwargs):
        if self.__class__ == Dataview:
            raise TypeError('Cannot directly instantiate Dataview objects')

        self.cmap = cmap if cmap is not None else default_cmap
        self.vmin = vmin
        self.vmax = vmax
        self.state = state
        self.attrs = kwargs
        if 'priority' not in self.attrs:
            self.attrs['priority'] = 1
        self.description = description

    def copy(self, *args, **kwargs):
        kwargs.update(self.attrs)
        return self.__class__(*args,
            cmap=self.cmap,
            vmin=self.vmin,
            vmax=self.vmax,
            description=self.description,
            state=self.state,
            **kwargs)

    @property
    def priority(self):
        return self.attrs['priority']

    @priority.setter
    def priority(self, value):
        self.attrs['priority'] = value

    def to_json(self, simple=False):
        if simple:
            return dict()

        sdict = dict(
            state=self.state,
            attrs=self.attrs.copy(),
            desc=self.description)
        try:
            sdict.update(dict(
                cmap=[self.cmap],
                vmin=[self.vmin if self.vmin is not None else np.percentile(np.nan_to_num(self.data), 1)],
                vmax=[self.vmax if self.vmax is not None else np.percentile(np.nan_to_num(self.data), 99)]
                ))
        except AttributeError:
            pass
        return sdict

    @staticmethod
    def from_hdf(node):
        data = json.loads(node[0])
        desc = node[1]
        try:
            cmap = json.loads(node[2])
        except:
            cmap = node[2]
        vmin = json.loads(node[3])
        vmax = json.loads(node[4])
        state = json.loads(node[5])
        attrs = json.loads(node[6])
        try:
            xfmname = json.loads(node[7])
        except ValueError:
            xfmname = None

        if not isinstance(vmin, list):
            vmin = [vmin]
        if not isinstance(vmax, list):
            vmax = [vmax]
        if not isinstance(cmap, list):
            cmap = [cmap]

        if len(data) == 1:
            xfm = None if xfmname is None else xfmname[0]
            return _from_hdf_view(node.file, data[0], xfmname=xfm, cmap=cmap[0], description=desc,
                vmin=vmin[0], vmax=vmax[0], state=state, **attrs)
        else:
            views = [_from_hdf_view(node.file, d, xfmname=x) for d, x in zip(data, xfname)]
            raise NotImplementedError

    def _write_hdf(self, h5, name="data", data=None, xfmname=None):
        views = h5.require_group("/views")
        view = views.require_dataset(name, (8,), h5py.special_dtype(vlen=str))
        view[0] = json.dumps(data)
        view[1] = self.description
        try:
            view[2] = json.dumps([self.cmap])
            view[3] = json.dumps([self.vmin])
            view[4] = json.dumps([self.vmax])
        except AttributeError:
            #For VolumeRGB/Vertex, there is no cmap/vmin/vmax
            view[2] = None
            view[3:5] = "null"
        view[5] = json.dumps(self.state)
        view[6] = json.dumps(self.attrs)
        view[7] = json.dumps(xfmname)
        return view

    @property
    def raw(self):
        from matplotlib import colors, cm, pyplot as plt
        import glob, os
        # Get colormap from matplotlib or pycortex colormaps
        ## -- redundant code, here and in cortex/quicklflat.py -- ##
        if isinstance(self.cmap,(str,unicode)):
            if not self.cmap in cm.__dict__:
                # unknown colormap, test whether it's in pycortex colormaps
                cmapdir = options.config.get('webgl', 'colormaps')
                colormaps = glob.glob(os.path.join(cmapdir, "*.png"))
                colormaps = dict(((os.path.split(c)[1][:-4],c) for c in colormaps))
                if not self.cmap in colormaps:
                    raise Exception('Unkown color map!')
                I = plt.imread(colormaps[self.cmap])
                cmap = colors.ListedColormap(np.squeeze(I))
                # Register colormap while we're at it
                cm.register_cmap(self.cmap,cmap)
            else:
                cmap = cm.get_cmap(self.cmap)
        norm = colors.Normalize(self.vmin, self.vmax) # Does this do anything?
        return np.rollaxis(cmap(self.data), -1)

class Multiview(Dataview):
    def __init__(self, views, description=""):
        for view in views:
            if not isinstance(view, Dataview):
                raise TypeError("Must be a View object!")
        raise NotImplementedError
        self.views = views

    def uniques(self, collapse=False):
        for view in self.views:
            for sv in view.uniques(collapse=collapse):
                yield sv

class Volume(VolumeData, Dataview):
    def __init__(self, data, subject, xfmname, mask=None,
        cmap=None, vmin=None, vmax=None, description="", **kwargs):
        super(Volume, self).__init__(data, subject, xfmname, mask=mask,
            cmap=cmap, vmin=vmin, vmax=vmax, description=description, **kwargs)

    def _write_hdf(self, h5, name="data"):
        datanode = VolumeData._write_hdf(self, h5)
        viewnode = Dataview._write_hdf(self, h5, name=name,
            data=[self.name], xfmname=[self.xfmname])
        return viewnode

    @property
    def raw(self):
        r, g, b, a = super(Volume, self).raw
        return VolumeRGB(r, g, b, self.subject, self.xfmname, a,
            description=self.description, state=self.state, **self.attrs)

class Vertex(VertexData, Dataview):
    def __init__(self, data, subject, cmap=None, vmin=None, vmax=None, description="", **kwargs):
        super(Vertex, self).__init__(data, subject, cmap=cmap, vmin=vmin, vmax=vmax,
            description=description, **kwargs)

    def _write_hdf(self, h5, name="data"):
        datanode = VertexData._write_hdf(self, h5)
        viewnode = Dataview._write_hdf(self, h5, name=name, data=[self.name])
        return viewnode

    @property
    def raw(self):
        r, g, b, a = super(Vertex, self).raw
        return VertexRGB(r, g, b, self.subject, a,
            description=self.description, state=self.state, **self.attrs)

from .viewRGB import VolumeRGB, VertexRGB
from .view2D import Volume2D, Vertex2D
<|endoftext|>


<commit_before>"""
A fake implementation of VWS.
"""

import json
import numbers
import uuid
from datetime import datetime, timedelta
from json.decoder import JSONDecodeError
from typing import Any, Callable, Dict, List, Tuple, Union  # noqa F401

import wrapt
from requests import codes
from requests_mock import DELETE, GET, POST, PUT
from requests_mock.request import _RequestObjectProxy
from requests_mock.response import _Context

from common.constants import ResultCodes
from vws._request_utils import authorization_header

@wrapt.decorator
def validate_authorization(wrapped: Callable[..., str],
                           instance: 'MockVuforiaTargetAPI',
                           args: Tuple[_RequestObjectProxy, _Context],
                           kwargs: Dict) -> str:
    """
    Validate the authorization header given to a VWS endpoint.

    Args:
        wrapped: An endpoint function for `requests_mock`.
        instance: The class that the endpoint function is in.
        args: The arguments given to the endpoint function.
        kwargs: The keyword arguments given to the endpoint function.

    Returns:
        The result of calling the endpoint.
    """
    request, context = args
    if 'Authorization' not in request.headers:
        context.status_code = codes.UNAUTHORIZED  # noqa: E501 pylint: disable=no-member
        body = {
            'transaction_id': uuid.uuid4().hex,
            'result_code': ResultCodes.AUTHENTICATION_FAILURE.value,
        }
        return json.dumps(body)

    if request.text is None:
        content = b''
    else:
        content = bytes(request.text, encoding='utf-8')

    expected_authorization_header = authorization_header(
        access_key=bytes(instance.access_key, encoding='utf-8'),
        secret_key=bytes(instance.secret_key, encoding='utf-8'),
        method=request.method,
        content=content,
        content_type=request.headers.get('Content-Type', ''),
        date=request.headers.get('Date', ''),
        request_path=request.path,
    )

    if request.headers['Authorization'] != expected_authorization_header:
        context.status_code = codes.BAD_REQUEST  # noqa: E501 pylint: disable=no-member
        body = {
            'transaction_id': uuid.uuid4().hex,
            'result_code': ResultCodes.FAIL.value,
        }
        return json.dumps(body)

    return wrapped(*args, **kwargs)

@wrapt.decorator
def validate_date(wrapped: Callable[..., str],
                  instance: 'MockVuforiaTargetAPI',  # noqa: E501 pylint: disable=unused-argument
                  args: Tuple[_RequestObjectProxy, _Context],
                  kwargs: Dict) -> str:
    """
    Validate the date header given to a VWS endpoint.

    Args:
        wrapped: An endpoint function for `requests_mock`.
        instance: The class that the endpoint function is in.
        args: The arguments given to the endpoint function.
        kwargs: The keyword arguments given to the endpoint function.

    Returns:
        The result of calling the endpoint.
    """
    request, context = args

    try:
        date_from_header = datetime.strptime(
            request.headers['Date'],
            '%a, %d %b %Y %H:%M:%S GMT',
        )
    except (KeyError, ValueError):
        context.status_code = codes.BAD_REQUEST  # noqa: E501 pylint: disable=no-member
        body = {
            'transaction_id': uuid.uuid4().hex,
            'result_code': ResultCodes.FAIL.value,
        }
        return json.dumps(body)

    time_difference = datetime.now() - date_from_header
    maximum_time_difference = timedelta(minutes=5)

    if abs(time_difference) >= maximum_time_difference:
        context.status_code = codes.FORBIDDEN  # noqa: E501 pylint: disable=no-member

        body = {
            'transaction_id': uuid.uuid4().hex,
            'result_code': ResultCodes.REQUEST_TIME_TOO_SKEWED.value,
        }
        return json.dumps(body)

    return wrapped(*args, **kwargs)

class Route:
    """
    A container for the route details which `requests_mock` needs.

    We register routes with names, and when we have an instance to work with
    later.
    """

    def __init__(self, route_name: str, path_pattern: str,
                 methods: List[str]) -> None:
        """
        Args:
            route_name: The name of the method.
            path_pattern: The end part of a URL pattern. E.g. `/targets` or
                `/targets/.+`.
            methods: HTTP methods that map to the route function.

        Attributes:
            route_name: The name of the method.
            path_pattern: The end part of a URL pattern. E.g. `/targets` or
                `/targets/.+`.
            methods: HTTP methods that map to the route function.
            endpoint: The method `requests_mock` should call when the endpoint
                is requested.
        """
        self.route_name = route_name
        self.path_pattern = path_pattern
        self.methods = methods

ROUTES = set([])

def route(path_pattern: str, methods: List[str]) -> Callable[..., Callable]:
    """
    Register a decorated method so that it can be recognized as a route.

    Args:
        path_pattern: The end part of a URL pattern. E.g. `/targets` or
            `/targets/.+`.
        methods: HTTP methods that map to the route function.
    """
    def decorator(method: Callable[..., str]) -> Callable[
            ..., str]:
        """
        Register a decorated method so that it can be recognized as a route.

        Args:
            method: Method to register.

        Returns:
            The given `method` with no changes.
        """
        ROUTES.add(
            Route(
                route_name=method.__name__,
                path_pattern=path_pattern,
                methods=methods,
            )
        )
        # pylint is not very good with decorators
        # https://github.com/PyCQA/pylint/issues/259#issuecomment-267671718
        date_validated = validate_date(method)  # noqa: E501 pylint: disable=no-value-for-parameter
        authorization_validated = validate_authorization(date_validated)  # noqa: E501 pylint: disable=no-value-for-parameter
        return authorization_validated
    return decorator

class MockVuforiaTargetAPI:  # pylint: disable=no-self-use
    """
    A fake implementation of the Vuforia Target API.

    This implementation is tied to the implementation of `requests_mock`.
    """

    def __init__(self, access_key: str, secret_key: str) -> None:
        """
        Args:
            access_key: A VWS access key.
            secret_key: A VWS secret key.

        Attributes:
            access_key: A VWS access key.
            secret_key: A VWS secret key.
            routes: The `Route`s to be used in the mock.
        """
        self.access_key = access_key  # type: str
        self.secret_key = secret_key  # type: str

        self.routes = ROUTES  # type: Set[Route]

    @route(path_pattern='/targets', methods=[POST])
    def add_target(self,
                   request: _RequestObjectProxy,  # noqa: E501 pylint: disable=unused-argument
                   context: _Context) -> str:
        """
        Add a target.

        Fake implementation of
        https://library.vuforia.com/articles/Solution/How-to-Add-a-Target-Using-VWS-API
        """
        body = {}  # type: Dict[str, Union[str, int]]
        decoded_body = request.body.decode('ascii')

        valid = True

        try:
            request_body_json = json.loads(decoded_body)
        except JSONDecodeError:
            request_body_json = {}

        allowed_keys = {
            'name',
            'width',
            'image',
            'active_flag',
            'application_metadata',
        }
        valid = valid and all(key in allowed_keys for key in
                              request_body_json.keys())

        mandatory_keys = {
            'image',
            'width',
            'name',
        }

        valid = valid and all(name in request_body_json.keys() for name in
                              mandatory_keys)

        width = request_body_json.get('width')
        name = request_body_json.get('name')

        width_is_number = isinstance(width, numbers.Number)
        width_positive = width_is_number and width >= 0
        valid = valid and width_positive

        valid = valid and isinstance(name, str)
        valid = valid and 0 < len(name) < 65

        if not valid:
            context.status_code = codes.BAD_REQUEST  # noqa: E501 pylint: disable=no-member
            body = {
                'transaction_id': uuid.uuid4().hex,
                'result_code': ResultCodes.FAIL.value,
            }
            return json.dumps(body)

        image = request_body_json.get('image')
        import pdb; pdb.set_trace()
        context.status_code = codes.CREATED  # noqa: E501 pylint: disable=no-member
        body = {
            'transaction_id': uuid.uuid4().hex,
            'result_code': ResultCodes.TARGET_CREATED.value,
            'target_id': uuid.uuid4().hex,
        }
        return json.dumps(body)

    @route(path_pattern='/targets/.+', methods=[DELETE])
    def delete_target(self,
                      request: _RequestObjectProxy,  # noqa: E501 pylint: disable=unused-argument
                      context: _Context) -> str:
        """
        Delete a target.

        Fake implementation of
        https://library.vuforia.com/articles/Solution/How-To-Delete-a-Target-Using-the-VWS-API
        """
        body = {
            'transaction_id': uuid.uuid4().hex,
            'result_code': ResultCodes.UNKNOWN_TARGET.value,
        }  # type: Dict[str, str]
        context.status_code = codes.NOT_FOUND  # noqa: E501 pylint: disable=no-member

        return json.dumps(body)

    @route(path_pattern='/summary', methods=[GET])
    def database_summary(self,
                         request: _RequestObjectProxy,  # noqa: E501 pylint: disable=unused-argument
                         context: _Context) -> str:
        """
        Get a database summary report.

        Fake implementation of
        https://library.vuforia.com/articles/Solution/How-To-Get-a-Database-Summary-Report-Using-the-VWS-API
        """
        body = {}  # type: Dict[str, str]

        context.status_code = codes.OK  # pylint: disable=no-member
        body = {
            'result_code': ResultCodes.SUCCESS.value,
            'transaction_id': uuid.uuid4().hex,
            'name': '',
            'active_images': '',
            'inactive_images': '',
            'failed_images': '',
            'target_quota': '',
            'total_recos': '',
            'current_month_recos': '',
            'previous_month_recos': '',
            'processing_images': '',
            'reco_threshold': '',
            'request_quota': '',
            'request_usage': '',
        }
        return json.dumps(body)

    @route(path_pattern='/targets', methods=[GET])
    def target_list(self,
                    request: _RequestObjectProxy,  # noqa: E501 pylint: disable=unused-argument
                    context: _Context) -> str:
        """
        Get a list of all targets.

        Fake implementation of
        https://library.vuforia.com/articles/Solution/How-To-Get-a-Target-List-for-a-Cloud-Database-Using-the-VWS-API
        """
        body = {}  # type: Dict[str, Union[str, List[object]]]

        context.status_code = codes.OK  # pylint: disable=no-member
        body = {
            'transaction_id': uuid.uuid4().hex,
            'result_code': ResultCodes.SUCCESS.value,
            'results': [],
        }
        return json.dumps(body)

    @route(path_pattern='/targets/.+', methods=[GET])
    def get_target(self,
                   request: _RequestObjectProxy,  # noqa: E501 pylint: disable=unused-argument
                   context: _Context) -> str:
        """
        Get details of a target.

        Fake implementation of
        https://library.vuforia.com/articles/Solution/How-To-Retrieve-a-Target-Record-Using-the-VWS-API
        """
        body = {
            'transaction_id': uuid.uuid4().hex,
            'result_code': ResultCodes.UNKNOWN_TARGET.value,
        }  # type: Dict[str, str]
        context.status_code = codes.NOT_FOUND  # noqa: E501 pylint: disable=no-member

        return json.dumps(body)

    @route(path_pattern='/duplicates/.+', methods=[GET])
    def get_duplicates(self,
                       request: _RequestObjectProxy,  # noqa: E501 pylint: disable=unused-argument
                       context: _Context) -> str:
        """
        Get targets which may be considered duplicates of a given target.

        Fake implementation of
        https://library.vuforia.com/articles/Solution/How-To-Check-for-Duplicate-Targets-using-the-VWS-API
        """
        body = {
            'transaction_id': uuid.uuid4().hex,
            'result_code': ResultCodes.UNKNOWN_TARGET.value,
        }  # type: Dict[str, str]
        context.status_code = codes.NOT_FOUND  # noqa: E501 pylint: disable=no-member

        return json.dumps(body)

    @route(path_pattern='/targets/.+', methods=[PUT])
    def update_target(self,
                      request: _RequestObjectProxy,  # noqa: E501 pylint: disable=unused-argument
                      context: _Context) -> str:
        """
        Update a target.

        Fake implementation of
        https://library.vuforia.com/articles/Solution/How-To-Update-a-Target-Using-the-VWS-API
        """
        body = {
            'transaction_id': uuid.uuid4().hex,
            'result_code': ResultCodes.UNKNOWN_TARGET.value,
        }  # type: Dict[str, str]
        context.status_code = codes.NOT_FOUND  # noqa: E501 pylint: disable=no-member

        return json.dumps(body)

    @route(path_pattern='/summary/.+', methods=[GET])
    def target_summary(self,
                       request: _RequestObjectProxy,  # noqa: E501 pylint: disable=unused-argument
                       context: _Context) -> str:
        """
        Get a summary report for a target.

        Fake implementation of
        https://library.vuforia.com/articles/Solution/How-To-Retrieve-a-Target-Summary-Report-using-the-VWS-API
        """
        body = {
            'transaction_id': uuid.uuid4().hex,
            'result_code': ResultCodes.UNKNOWN_TARGET.value,
        }  # type: Dict[str, str]
        context.status_code = codes.NOT_FOUND  # noqa: E501 pylint: disable=no-member

        return json.dumps(body)
<commit_msg>Progress towards checking image type<commit_after>"""
A fake implementation of VWS.
"""

import base64
import imghdr
import io
import json
import numbers
import uuid
from datetime import datetime, timedelta
from json.decoder import JSONDecodeError
from typing import Any, Callable, Dict, List, Tuple, Union  # noqa F401

import wrapt
from requests import codes
from requests_mock import DELETE, GET, POST, PUT
from requests_mock.request import _RequestObjectProxy
from requests_mock.response import _Context

from common.constants import ResultCodes
from vws._request_utils import authorization_header

@wrapt.decorator
def validate_authorization(wrapped: Callable[..., str],
                           instance: 'MockVuforiaTargetAPI',
                           args: Tuple[_RequestObjectProxy, _Context],
                           kwargs: Dict) -> str:
    """
    Validate the authorization header given to a VWS endpoint.

    Args:
        wrapped: An endpoint function for `requests_mock`.
        instance: The class that the endpoint function is in.
        args: The arguments given to the endpoint function.
        kwargs: The keyword arguments given to the endpoint function.

    Returns:
        The result of calling the endpoint.
    """
    request, context = args
    if 'Authorization' not in request.headers:
        context.status_code = codes.UNAUTHORIZED  # noqa: E501 pylint: disable=no-member
        body = {
            'transaction_id': uuid.uuid4().hex,
            'result_code': ResultCodes.AUTHENTICATION_FAILURE.value,
        }
        return json.dumps(body)

    if request.text is None:
        content = b''
    else:
        content = bytes(request.text, encoding='utf-8')

    expected_authorization_header = authorization_header(
        access_key=bytes(instance.access_key, encoding='utf-8'),
        secret_key=bytes(instance.secret_key, encoding='utf-8'),
        method=request.method,
        content=content,
        content_type=request.headers.get('Content-Type', ''),
        date=request.headers.get('Date', ''),
        request_path=request.path,
    )

    if request.headers['Authorization'] != expected_authorization_header:
        context.status_code = codes.BAD_REQUEST  # noqa: E501 pylint: disable=no-member
        body = {
            'transaction_id': uuid.uuid4().hex,
            'result_code': ResultCodes.FAIL.value,
        }
        return json.dumps(body)

    return wrapped(*args, **kwargs)

@wrapt.decorator
def validate_date(wrapped: Callable[..., str],
                  instance: 'MockVuforiaTargetAPI',  # noqa: E501 pylint: disable=unused-argument
                  args: Tuple[_RequestObjectProxy, _Context],
                  kwargs: Dict) -> str:
    """
    Validate the date header given to a VWS endpoint.

    Args:
        wrapped: An endpoint function for `requests_mock`.
        instance: The class that the endpoint function is in.
        args: The arguments given to the endpoint function.
        kwargs: The keyword arguments given to the endpoint function.

    Returns:
        The result of calling the endpoint.
    """
    request, context = args

    try:
        date_from_header = datetime.strptime(
            request.headers['Date'],
            '%a, %d %b %Y %H:%M:%S GMT',
        )
    except (KeyError, ValueError):
        context.status_code = codes.BAD_REQUEST  # noqa: E501 pylint: disable=no-member
        body = {
            'transaction_id': uuid.uuid4().hex,
            'result_code': ResultCodes.FAIL.value,
        }
        return json.dumps(body)

    time_difference = datetime.now() - date_from_header
    maximum_time_difference = timedelta(minutes=5)

    if abs(time_difference) >= maximum_time_difference:
        context.status_code = codes.FORBIDDEN  # noqa: E501 pylint: disable=no-member

        body = {
            'transaction_id': uuid.uuid4().hex,
            'result_code': ResultCodes.REQUEST_TIME_TOO_SKEWED.value,
        }
        return json.dumps(body)

    return wrapped(*args, **kwargs)

class Route:
    """
    A container for the route details which `requests_mock` needs.

    We register routes with names, and when we have an instance to work with
    later.
    """

    def __init__(self, route_name: str, path_pattern: str,
                 methods: List[str]) -> None:
        """
        Args:
            route_name: The name of the method.
            path_pattern: The end part of a URL pattern. E.g. `/targets` or
                `/targets/.+`.
            methods: HTTP methods that map to the route function.

        Attributes:
            route_name: The name of the method.
            path_pattern: The end part of a URL pattern. E.g. `/targets` or
                `/targets/.+`.
            methods: HTTP methods that map to the route function.
            endpoint: The method `requests_mock` should call when the endpoint
                is requested.
        """
        self.route_name = route_name
        self.path_pattern = path_pattern
        self.methods = methods

ROUTES = set([])

def route(path_pattern: str, methods: List[str]) -> Callable[..., Callable]:
    """
    Register a decorated method so that it can be recognized as a route.

    Args:
        path_pattern: The end part of a URL pattern. E.g. `/targets` or
            `/targets/.+`.
        methods: HTTP methods that map to the route function.
    """
    def decorator(method: Callable[..., str]) -> Callable[
            ..., str]:
        """
        Register a decorated method so that it can be recognized as a route.

        Args:
            method: Method to register.

        Returns:
            The given `method` with no changes.
        """
        ROUTES.add(
            Route(
                route_name=method.__name__,
                path_pattern=path_pattern,
                methods=methods,
            )
        )
        # pylint is not very good with decorators
        # https://github.com/PyCQA/pylint/issues/259#issuecomment-267671718
        date_validated = validate_date(method)  # noqa: E501 pylint: disable=no-value-for-parameter
        authorization_validated = validate_authorization(date_validated)  # noqa: E501 pylint: disable=no-value-for-parameter
        return authorization_validated
    return decorator

class MockVuforiaTargetAPI:  # pylint: disable=no-self-use
    """
    A fake implementation of the Vuforia Target API.

    This implementation is tied to the implementation of `requests_mock`.
    """

    def __init__(self, access_key: str, secret_key: str) -> None:
        """
        Args:
            access_key: A VWS access key.
            secret_key: A VWS secret key.

        Attributes:
            access_key: A VWS access key.
            secret_key: A VWS secret key.
            routes: The `Route`s to be used in the mock.
        """
        self.access_key = access_key  # type: str
        self.secret_key = secret_key  # type: str

        self.routes = ROUTES  # type: Set[Route]

    @route(path_pattern='/targets', methods=[POST])
    def add_target(self,
                   request: _RequestObjectProxy,  # noqa: E501 pylint: disable=unused-argument
                   context: _Context) -> str:
        """
        Add a target.

        Fake implementation of
        https://library.vuforia.com/articles/Solution/How-to-Add-a-Target-Using-VWS-API
        """
        body = {}  # type: Dict[str, Union[str, int]]
        decoded_body = request.body.decode('ascii')

        valid = True

        try:
            request_body_json = json.loads(decoded_body)
        except JSONDecodeError:
            request_body_json = {}

        allowed_keys = {
            'name',
            'width',
            'image',
            'active_flag',
            'application_metadata',
        }
        valid = valid and all(key in allowed_keys for key in
                              request_body_json.keys())

        mandatory_keys = {
            'image',
            'width',
            'name',
        }

        valid = valid and all(name in request_body_json.keys() for name in
                              mandatory_keys)

        width = request_body_json.get('width')
        name = request_body_json.get('name')

        width_is_number = isinstance(width, numbers.Number)
        width_positive = width_is_number and width >= 0
        valid = valid and width_positive

        valid = valid and isinstance(name, str)
        valid = valid and 0 < len(name) < 65

        if not valid:
            context.status_code = codes.BAD_REQUEST  # noqa: E501 pylint: disable=no-member
            body = {
                'transaction_id': uuid.uuid4().hex,
                'result_code': ResultCodes.FAIL.value,
            }
            return json.dumps(body)

        image = request_body_json.get('image')
        decoded = base64.b64decode(image)
        image_file = io.BytesIO(decoded)
        image_file_type = imghdr.what(image_file)

        if image_file_type not in ('png', 'jpeg'):
            context.status_code = codes.UNPROCESSABLE_ENTITY  # noqa: E501 pylint: disable=no-member
            body = {
                'transaction_id': uuid.uuid4().hex,
                'result_code': ResultCodes.BAD_IMAGE.value,
                'target_id': uuid.uuid4().hex,
            }
            return json.dumps(body)

        context.status_code = codes.CREATED  # noqa: E501 pylint: disable=no-member
        body = {
            'transaction_id': uuid.uuid4().hex,
            'result_code': ResultCodes.TARGET_CREATED.value,
            'target_id': uuid.uuid4().hex,
        }
        return json.dumps(body)

    @route(path_pattern='/targets/.+', methods=[DELETE])
    def delete_target(self,
                      request: _RequestObjectProxy,  # noqa: E501 pylint: disable=unused-argument
                      context: _Context) -> str:
        """
        Delete a target.

        Fake implementation of
        https://library.vuforia.com/articles/Solution/How-To-Delete-a-Target-Using-the-VWS-API
        """
        body = {
            'transaction_id': uuid.uuid4().hex,
            'result_code': ResultCodes.UNKNOWN_TARGET.value,
        }  # type: Dict[str, str]
        context.status_code = codes.NOT_FOUND  # noqa: E501 pylint: disable=no-member

        return json.dumps(body)

    @route(path_pattern='/summary', methods=[GET])
    def database_summary(self,
                         request: _RequestObjectProxy,  # noqa: E501 pylint: disable=unused-argument
                         context: _Context) -> str:
        """
        Get a database summary report.

        Fake implementation of
        https://library.vuforia.com/articles/Solution/How-To-Get-a-Database-Summary-Report-Using-the-VWS-API
        """
        body = {}  # type: Dict[str, str]

        context.status_code = codes.OK  # pylint: disable=no-member
        body = {
            'result_code': ResultCodes.SUCCESS.value,
            'transaction_id': uuid.uuid4().hex,
            'name': '',
            'active_images': '',
            'inactive_images': '',
            'failed_images': '',
            'target_quota': '',
            'total_recos': '',
            'current_month_recos': '',
            'previous_month_recos': '',
            'processing_images': '',
            'reco_threshold': '',
            'request_quota': '',
            'request_usage': '',
        }
        return json.dumps(body)

    @route(path_pattern='/targets', methods=[GET])
    def target_list(self,
                    request: _RequestObjectProxy,  # noqa: E501 pylint: disable=unused-argument
                    context: _Context) -> str:
        """
        Get a list of all targets.

        Fake implementation of
        https://library.vuforia.com/articles/Solution/How-To-Get-a-Target-List-for-a-Cloud-Database-Using-the-VWS-API
        """
        body = {}  # type: Dict[str, Union[str, List[object]]]

        context.status_code = codes.OK  # pylint: disable=no-member
        body = {
            'transaction_id': uuid.uuid4().hex,
            'result_code': ResultCodes.SUCCESS.value,
            'results': [],
        }
        return json.dumps(body)

    @route(path_pattern='/targets/.+', methods=[GET])
    def get_target(self,
                   request: _RequestObjectProxy,  # noqa: E501 pylint: disable=unused-argument
                   context: _Context) -> str:
        """
        Get details of a target.

        Fake implementation of
        https://library.vuforia.com/articles/Solution/How-To-Retrieve-a-Target-Record-Using-the-VWS-API
        """
        body = {
            'transaction_id': uuid.uuid4().hex,
            'result_code': ResultCodes.UNKNOWN_TARGET.value,
        }  # type: Dict[str, str]
        context.status_code = codes.NOT_FOUND  # noqa: E501 pylint: disable=no-member

        return json.dumps(body)

    @route(path_pattern='/duplicates/.+', methods=[GET])
    def get_duplicates(self,
                       request: _RequestObjectProxy,  # noqa: E501 pylint: disable=unused-argument
                       context: _Context) -> str:
        """
        Get targets which may be considered duplicates of a given target.

        Fake implementation of
        https://library.vuforia.com/articles/Solution/How-To-Check-for-Duplicate-Targets-using-the-VWS-API
        """
        body = {
            'transaction_id': uuid.uuid4().hex,
            'result_code': ResultCodes.UNKNOWN_TARGET.value,
        }  # type: Dict[str, str]
        context.status_code = codes.NOT_FOUND  # noqa: E501 pylint: disable=no-member

        return json.dumps(body)

    @route(path_pattern='/targets/.+', methods=[PUT])
    def update_target(self,
                      request: _RequestObjectProxy,  # noqa: E501 pylint: disable=unused-argument
                      context: _Context) -> str:
        """
        Update a target.

        Fake implementation of
        https://library.vuforia.com/articles/Solution/How-To-Update-a-Target-Using-the-VWS-API
        """
        body = {
            'transaction_id': uuid.uuid4().hex,
            'result_code': ResultCodes.UNKNOWN_TARGET.value,
        }  # type: Dict[str, str]
        context.status_code = codes.NOT_FOUND  # noqa: E501 pylint: disable=no-member

        return json.dumps(body)

    @route(path_pattern='/summary/.+', methods=[GET])
    def target_summary(self,
                       request: _RequestObjectProxy,  # noqa: E501 pylint: disable=unused-argument
                       context: _Context) -> str:
        """
        Get a summary report for a target.

        Fake implementation of
        https://library.vuforia.com/articles/Solution/How-To-Retrieve-a-Target-Summary-Report-using-the-VWS-API
        """
        body = {
            'transaction_id': uuid.uuid4().hex,
            'result_code': ResultCodes.UNKNOWN_TARGET.value,
        }  # type: Dict[str, str]
        context.status_code = codes.NOT_FOUND  # noqa: E501 pylint: disable=no-member

        return json.dumps(body)
<|endoftext|>


<commit_before>from django.conf.urls import patterns, include, url
from django.core.exceptions import ObjectDoesNotExist, MultipleObjectsReturned
from tastypie.resources import ModelResource
from tastypie.constants import ALL, ALL_WITH_RELATIONS
from tastypie.utils import trailing_slash
from tastypie.cache import SimpleCache
from tastypie.cache import NoCache
from tastypie.authorization import Authorization
from tastypie.http import HttpGone
from tastypie import fields
from course_selection.models import *

class SemesterResource(ModelResource):
    class Meta:
        queryset = Semester.objects.all()
        resource_name = 'semester'
        excludes = ['']
        allowed_methods = ['get']
        authorization = Authorization()
        filtering = {
            'term_code': ALL
        }

    def dehydrate(self, bundle):
        # give the semester a readable name
        term_code = bundle.data['term_code']
        end_year = int(term_code[1:3])
        start_year = end_year - 1
        if int(term_code[-1]) == 2:
            sem = 'Fall'
        else:
            sem = 'Spring'
        name = str(start_year) + '-' + str(end_year) + ' ' + sem

        bundle.data['name'] = name
        return bundle

    def prepend_urls(self):
        return [
            #url(r"^(?P<resource_name>%s)/(?P<term_code>[\w\d_.-]+)/$" % self._meta.resource_name, self.wrap_view('dispatch_detail'), name="api_dispatch_detail"),
            #url(r"^(?P<resource_name>%s)/(?P<term_code>[\w\d_.-]+)/course%s$" % (self._meta.resource_name, trailing_slash()), self.wrap_view('get_course'), name="api_get_course"),
        ]

    #def get_course(self, request, **kwargs):
    #    try:
    #        bundle = self.build_bundle(data={'term_code': kwargs['term_code']}, request=request)
    #        obj = self.cached_obj_get(bundle=bundle, **self.remove_api_resource_names(kwargs))
    #    except ObjectDoesNotExist:
    #        return HttpGone()
    #    except MultipleObjectsReturned:
    #        return HttpMultipleChoices("More than one resource is found at this URI.")

    #    course_resource = CourseResource()
    #    return course_resource.get_list(request, semester=obj.pk)

class CourseListingResource(ModelResource):
    course = fields.ForeignKey('course_selection.api.CourseResource', 'course')

    class Meta:
        queryset = Course_Listing.objects.all()
        resource_name = 'course_listing'
        excludes = ['course', '']
        allowed_methods = ['get']
        cache = SimpleCache(timeout=10)

class CourseResource(ModelResource):
    semester = fields.ForeignKey(SemesterResource, 'semester', full=True)
    course_listings = fields.ToManyField(CourseListingResource, 'course_listing_set', null=True, full=True)
    sections = fields.ToManyField('course_selection.api.SectionResource', 'sections', full=True)

    def alter_list_data_to_serialize(self, request, data):
        if request.GET.get('meta_only'):
            return {'meta': data['meta']}
        return data

    class Meta:
        queryset = Course.objects.all()
        resource_name = 'course'
        excludes = ['']
        allowed_methods = ['get']
        cache = SimpleCache(timeout=10)
        limit = 0
        max_limit = 0
        filtering = {
            'semester' : ALL_WITH_RELATIONS
        }

class SectionResource(ModelResource):
    course = fields.ForeignKey(CourseResource, 'course')
    meetings = fields.ToManyField('course_selection.api.MeetingResource', 'meetings', full=True)

    class Meta:
        queryset = Section.objects.all()
        resource_name = 'section'
        excludes = ['isDefault']
        allowed_methods = ['get']
        cache = SimpleCache(timeout=10)

class MeetingResource(ModelResource):
    section = fields.ForeignKey(SectionResource, 'section')

    class Meta:
        queryset = Meeting.objects.all()
        resource_name = 'meeting'
        excludes = ['']
        allowed_methods = ['get']
        cache = SimpleCache(timeout=10)

class ColorPaletteResource(ModelResource):
    class Meta:
        queryset = Color_Palette.objects.all()
        resource_name = 'color_palette'
        excludes = ['']
        allowed_methods = ['get']
        cache = SimpleCache(timeout=10)

# class EnrollmentResource(ModelResource):
#     class Meta:
#         queryset = Enrollment.objects.all()
#         resource_name = 'enrollment'
#         allowed_methods = []

class ScheduleResource(ModelResource):
    #enrollments = fields.ToManyField(EnrollmentResource, 'enrollments', full=True, null=True)
    semester = fields.ForeignKey(SemesterResource, 'semester', full=True)
    user = fields.ForeignKey('course_selection.api.UserResource', 'user')

    class Meta:
        queryset = Schedule.objects.all()
        resource_name = 'schedule'
        excludes = []
        allowed_methods = ['get', 'post', 'put', 'delete']
        cache = NoCache()
        authorization = Authorization()
        always_return_data = True
        limit = 0
        max_limit = 0
        filtering = {
            'user': ALL_WITH_RELATIONS,
            'semester': ALL_WITH_RELATIONS
        }

    # def obj_create(self, bundle, **kwargs):
    #     import pdb; pdb.set_trace()
    #     return super(ScheduleResource, self).obj_create(bundle, user=bundle.request.user)

    # def apply_authorization_limits(self, request, object_list):
    #     import pdb; pdb.set_trace()
    #     return object_list.filter(user=request.user)

class UserResource(ModelResource):
    class Meta:
        queryset = Nice_User.objects.all()
        resource_name= 'user'
        excludes = ['password']
        allowed_methods = ['get']
        cache = SimpleCache(timeout=10)
        authorization = Authorization()
        filtering = {
            'netid': ALL_WITH_RELATIONS
        }

    def prepend_urls(self):
        return [
            #url(r"^(?P<resource_name>%s)/(?P<netid>[\w\d_.-]+)/$" % self._meta.resource_name, self.wrap_view('dispatch_detail'), name="api_dispatch_detail"),
            url(r"^(?P<resource_name>%s)/(?P<pk>\w[\w/-]*)/schedule%s$" % (self._meta.resource_name, trailing_slash()), self.wrap_view('get_schedule'), name="api_get_schedule"),
        ]

    def get_schedule(self, request, **kwargs):
        try:
            bundle = self.build_bundle(data={'pk': kwargs['pk']}, request=request)
            obj = self.cached_obj_get(bundle=bundle, **self.remove_api_resource_names(kwargs))
        except ObjectDoesNotExist:
            return HttpGone()
        except MultipleObjectsReturned:
            return HttpMultipleChoices("More than one resource is found at this URI.")

        schedule_resource = ScheduleResource()
        return schedule_resource.get_list(request, user=4991)

class ProfessorResource(ModelResource):
    class Meta:
        queryset = Professor.objects.all()
        resource_name = 'professor'
        excludes = []
        allowed_methods = ['get', 'post', 'put']
        authorization = Authorization()
<commit_msg>added authorization for schedules and users<commit_after>from django.conf.urls import patterns, include, url
from django.core.exceptions import ObjectDoesNotExist, MultipleObjectsReturned
from tastypie.resources import ModelResource
from tastypie.constants import ALL, ALL_WITH_RELATIONS
from tastypie.utils import trailing_slash
from tastypie.cache import SimpleCache
from tastypie.cache import NoCache
from tastypie.authorization import Authorization, ReadOnlyAuthorization
from tastypie.exceptions import Unauthorized
from tastypie.http import HttpGone
from tastypie import fields
from course_selection.models import *

class UserAuthorization(Authorization):
    def read_list(self, object_list, bundle):
        # This assumes a ``QuerySet`` from ``ModelResource``.
        return [obj for obj in object_list if obj.netid == bundle.request.user.username]
        #return object_list.filter(user=bundle.request.user)

    def read_detail(self, object_list, bundle):
        # Is the requested object owned by the user?
        return bundle.obj.netid == bundle.request.user.username

    def create_list(self, object_list, bundle):
        # Assuming they're auto-assigned to ``user``.
        return [obj for obj in object_list if obj.netid == bundle.request.user.username]

    def create_detail(self, object_list, bundle):
        return bundle.obj.netid == bundle.request.user.username
        #return bundle.obj.user == bundle.request.user

    def update_list(self, object_list, bundle):
        return [obj for obj in object_list if obj.netid == bundle.request.user.username]

        #allowed = []

        ## Since they may not all be saved, iterate over them.
        #for obj in object_list:
        #    if obj.user == bundle.request.user:
        #        allowed.append(obj)

        #return allowed

    def update_detail(self, object_list, bundle):
        return bundle.obj.netid == bundle.request.user.username

    def delete_list(self, object_list, bundle):
        # Sorry user, no deletes for you!
        raise Unauthorized("Sorry, no deletes.")

    def delete_detail(self, object_list, bundle):
        raise Unauthorized("Sorry, no deletes.")

class UserObjectsOnlyAuthorization(Authorization):
    def read_list(self, object_list, bundle):
        # This assumes a ``QuerySet`` from ``ModelResource``.
        return [obj for obj in object_list if obj.user.netid == bundle.request.user.username]
        #return object_list.filter(user=bundle.request.user)

    def read_detail(self, object_list, bundle):
        # Is the requested object owned by the user?
        return bundle.obj.user.netid == bundle.request.user.username

    def create_list(self, object_list, bundle):
        # Assuming they're auto-assigned to ``user``.
        return [obj for obj in object_list if obj.user.netid == bundle.request.user.username]

    def create_detail(self, object_list, bundle):
        return bundle.obj.user.netid == bundle.request.user.username
        #return bundle.obj.user == bundle.request.user

    def update_list(self, object_list, bundle):
        return [obj for obj in object_list if obj.user.netid == bundle.request.user.username]

        #allowed = []

        ## Since they may not all be saved, iterate over them.
        #for obj in object_list:
        #    if obj.user == bundle.request.user:
        #        allowed.append(obj)

        #return allowed

    def update_detail(self, object_list, bundle):
        return bundle.obj.user.netid == bundle.request.user.username

    def delete_list(self, object_list, bundle):
        # Sorry user, no deletes for you!
        # raise Unauthorized("Sorry, no deletes.")
        return [obj for obj in object_list if obj.user.netid == bundle.request.user.username]
        #return object_list

    def delete_detail(self, object_list, bundle):
        return bundle.obj.user.netid == bundle.request.user.username
        #raise Unauthorized("Sorry, no deletes.")

class SemesterResource(ModelResource):
    class Meta:
        queryset = Semester.objects.all()
        resource_name = 'semester'
        excludes = ['']
        allowed_methods = ['get']
        authorization = Authorization()
        filtering = {
            'term_code': ALL
        }

    def dehydrate(self, bundle):
        # give the semester a readable name
        term_code = bundle.data['term_code']
        end_year = int(term_code[1:3])
        start_year = end_year - 1
        if int(term_code[-1]) == 2:
            sem = 'Fall'
        else:
            sem = 'Spring'
        name = str(start_year) + '-' + str(end_year) + ' ' + sem

        bundle.data['name'] = name
        return bundle

    def prepend_urls(self):
        return [
            #url(r"^(?P<resource_name>%s)/(?P<term_code>[\w\d_.-]+)/$" % self._meta.resource_name, self.wrap_view('dispatch_detail'), name="api_dispatch_detail"),
            #url(r"^(?P<resource_name>%s)/(?P<term_code>[\w\d_.-]+)/course%s$" % (self._meta.resource_name, trailing_slash()), self.wrap_view('get_course'), name="api_get_course"),
        ]

    #def get_course(self, request, **kwargs):
    #    try:
    #        bundle = self.build_bundle(data={'term_code': kwargs['term_code']}, request=request)
    #        obj = self.cached_obj_get(bundle=bundle, **self.remove_api_resource_names(kwargs))
    #    except ObjectDoesNotExist:
    #        return HttpGone()
    #    except MultipleObjectsReturned:
    #        return HttpMultipleChoices("More than one resource is found at this URI.")

    #    course_resource = CourseResource()
    #    return course_resource.get_list(request, semester=obj.pk)

class CourseListingResource(ModelResource):
    course = fields.ForeignKey('course_selection.api.CourseResource', 'course')

    class Meta:
        queryset = Course_Listing.objects.all()
        resource_name = 'course_listing'
        excludes = ['course', '']
        allowed_methods = ['get']
        cache = SimpleCache(timeout=10)

class CourseResource(ModelResource):
    semester = fields.ForeignKey(SemesterResource, 'semester', full=True)
    course_listings = fields.ToManyField(CourseListingResource, 'course_listing_set', null=True, full=True)
    sections = fields.ToManyField('course_selection.api.SectionResource', 'sections', full=True)

    def alter_list_data_to_serialize(self, request, data):
        if request.GET.get('meta_only'):
            return {'meta': data['meta']}
        return data

    class Meta:
        queryset = Course.objects.all()
        resource_name = 'course'
        excludes = ['']
        allowed_methods = ['get']
        cache = SimpleCache(timeout=10)
        limit = 0
        max_limit = 0
        filtering = {
            'semester' : ALL_WITH_RELATIONS
        }

class SectionResource(ModelResource):
    course = fields.ForeignKey(CourseResource, 'course')
    meetings = fields.ToManyField('course_selection.api.MeetingResource', 'meetings', full=True)

    class Meta:
        queryset = Section.objects.all()
        resource_name = 'section'
        excludes = ['isDefault']
        allowed_methods = ['get']
        cache = SimpleCache(timeout=10)

class MeetingResource(ModelResource):
    section = fields.ForeignKey(SectionResource, 'section')

    class Meta:
        queryset = Meeting.objects.all()
        resource_name = 'meeting'
        excludes = ['']
        allowed_methods = ['get']
        cache = SimpleCache(timeout=10)

class ColorPaletteResource(ModelResource):
    class Meta:
        queryset = Color_Palette.objects.all()
        resource_name = 'color_palette'
        excludes = ['']
        allowed_methods = ['get']
        cache = SimpleCache(timeout=10)

# class EnrollmentResource(ModelResource):
#     class Meta:
#         queryset = Enrollment.objects.all()
#         resource_name = 'enrollment'
#         allowed_methods = []

class ScheduleResource(ModelResource):
    #enrollments = fields.ToManyField(EnrollmentResource, 'enrollments', full=True, null=True)
    semester = fields.ForeignKey(SemesterResource, 'semester', full=True)
    user = fields.ForeignKey('course_selection.api.UserResource', 'user')

    class Meta:
        queryset = Schedule.objects.all()
        resource_name = 'schedule'
        excludes = []
        allowed_methods = ['get', 'post', 'put', 'delete']
        cache = NoCache()
        authorization = UserObjectsOnlyAuthorization()
        always_return_data = True
        limit = 0
        max_limit = 0
        filtering = {
            'user': ALL_WITH_RELATIONS,
            'semester': ALL_WITH_RELATIONS
        }

    # def obj_create(self, bundle, **kwargs):
    #     import pdb; pdb.set_trace()
    #     return super(ScheduleResource, self).obj_create(bundle, user=bundle.request.user)

    # def apply_authorization_limits(self, request, object_list):
    #     import pdb; pdb.set_trace()
    #     return object_list.filter(user=request.user)

class UserResource(ModelResource):
    class Meta:
        queryset = Nice_User.objects.all()
        resource_name= 'user'
        excludes = ['password']
        allowed_methods = ['get']
        cache = SimpleCache(timeout=10)
        authorization = UserAuthorization()
        filtering = {
            'netid': ALL_WITH_RELATIONS
        }

    def prepend_urls(self):
        return [
            #url(r"^(?P<resource_name>%s)/(?P<netid>[\w\d_.-]+)/$" % self._meta.resource_name, self.wrap_view('dispatch_detail'), name="api_dispatch_detail"),
            url(r"^(?P<resource_name>%s)/(?P<pk>\w[\w/-]*)/schedule%s$" % (self._meta.resource_name, trailing_slash()), self.wrap_view('get_schedule'), name="api_get_schedule"),
        ]

    def get_schedule(self, request, **kwargs):
        try:
            bundle = self.build_bundle(data={'pk': kwargs['pk']}, request=request)
            obj = self.cached_obj_get(bundle=bundle, **self.remove_api_resource_names(kwargs))
        except ObjectDoesNotExist:
            return HttpGone()
        except MultipleObjectsReturned:
            return HttpMultipleChoices("More than one resource is found at this URI.")

        schedule_resource = ScheduleResource()
        return schedule_resource.get_list(request, user=4991)

class ProfessorResource(ModelResource):
    class Meta:
        queryset = Professor.objects.all()
        resource_name = 'professor'
        excludes = []
        allowed_methods = ['get', 'post', 'put']
        authorization = Authorization()
<|endoftext|>


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

"""
@package
@file utils
@author Christopher Mueller
@brief
"""

import numpy as np
import uuid
import re
import math

def create_guid():
    """
    @retval Return global unique id string
    """
    # guids seem to be more readable if they are UPPERCASE
    return str(uuid.uuid4()).upper()

def is_guid(str_val):
    guid_match = r'^\w{8}-\w{4}-\w{4}-\w{4}-\w{12}'
    return re.match(guid_match, str_val) is not None

def prod(lst):
    import operator
    return reduce(operator.mul, lst, 1)

def is_valid_constraint(v):
    ret = False
    if isinstance(v, (slice, int)) or\
       (isinstance(v, (list,tuple)) and np.array([is_valid_constraint(e) for e in v]).all()):
        ret = True

    return ret

def find_nearest_index(seq, val):
    """
    Returns the index of the value in the array-like object arr nearest to val.

    seq is viewed as a numpy array using numpy.asanyarray()

    If seq contains duplicates, the first match is returned

    @param seq  The array-like object to search
    @param val  The value to search for
    @return     The index nearest to val
    """
    idx = np.abs(np.asanyarray(seq)-val).argmin()
    return idx

def find_nearest_value(seq, val):
    """
    Returns the value in the array-like object arr nearest to but not greater than val.

    seq is viewed as a numpy array using numpy.asanyarray()

    If seq contains duplicates, the first match is returned

    @param seq  The array-like object to search
    @param val  The value to search for
    @return     The value nearest to but not greater than val
    """
    a = np.asanyarray(seq)
    idx = find_nearest_index(a, val)
    fv = a.flat[idx]
    if val < fv:
        return a.flat[idx-1]
    else:
        return fv

def _raise_index_error_int(slice_, size, dim):
    if slice_ < 0:
        raise IndexError('On dimension {0}; index cannot be < 0: index => {0}'.format(dim, slice_))
    if slice_ >= size:
        raise IndexError('On dimension {0}; index cannot be >= the size: index => {1}, size => {2}'.format(dim, slice_, size))

def _raise_index_error_list(slice_, size, dim):
    last = -1
    for i in xrange(len(slice_)):
        c=slice_[i]
        if last >= c:
            raise IndexError('On dimension {0}; indices must be in increasing order and cannot be duplicated: list => {1}'.format(dim, slice_))
        last = c
        if slice_[i] >= size:
            raise IndexError('On dimension {0}; index {1} of list cannot be >= the size: list => {2}, size => {3}'.format(dim, i, slice_, size))

def _raise_index_error_slice(slice_, size, dim):
    if slice_.start is not None:
        if slice_.start < 0:
            raise IndexError('On dimension {0}; start index of slice cannot be < 0: slice => {1}, size => {2}'.format(dim, slice_, size))
        if slice_.start >= size:
            raise IndexError('On dimension {0}; start index of slice cannot be >= size: slice => {1}, size => {2}'.format(dim, slice_, size))
    if slice_.stop is not None:
        if slice_.start is None and slice_.stop == 0:
            raise IndexError('On dimension {0}; stop index of slice cannot be == 0 when the start index is None: slice => {1}, size => {2}'.format(dim, slice_, size))
        if slice_.stop < 0:
            raise IndexError('On dimension {0}; stop index of slice cannot be < 0: slice => {1}, size => {2}'.format(dim, slice_, size))
        # This case seems to be counter to how numpy functions - if a slice is longer than the shape, it's simply truncated to the appropriate size...
#        if slice_.stop > size:
#            raise IndexError('On dimension {0}; stop index of slice cannot be > size: slice => {1}, size => {2}'.format(dim, slice_, size))
    if slice_.start is not None and slice_.stop is not None:
        if slice_.start >= slice_.stop:
            raise IndexError('On dimension {0}; start index of slice cannot be >= stop index: slice => {1}'.format(dim, slice_))

def get_shape_from_slice(slice_, max_shp):
    shp=[]
    for i, s in enumerate(slice_):
        if isinstance(s, int):
            shp.append(1)
        elif isinstance(s, (list,tuple)):
            shp.append(len(s))
        elif isinstance(s, slice):
            st=min(s.stop, max_shp[i]) if s.stop is not None else max_shp[i]
            shp.append(len(range(*s.indices(st))))

    return tuple(shp)

def fix_slice(slice_, shape):
    # CBM: First swack - see this for more possible checks: http://code.google.com/p/netcdf4-python/source/browse/trunk/netCDF4_utils.py
    if not is_valid_constraint(slice_):
        raise SystemError('invalid constraint supplied: {0}'.format(slice_))

    # First, ensure we're working with a list so we can make edits...
    if not np.iterable(slice_):
        slice_ = [slice_,]
    elif not isinstance(slice_,list):
        slice_ = list(slice_)

    # If shape is an integer, tuplize it
    if isinstance(shape, int):
        shape = (shape,)

    # Then make sure it's the correct rank
    rank = len(shape)
    slen = len(slice_)
    if not slen == rank:
        if slen > rank:
            slice_ = slice_[:rank]
        else:
            for n in xrange(slen, rank):
                slice_.append(slice(None,None,None))

    # Next, deal with negative indices and check for IndexErrors
    # Logic for handling negative indices from: http://docs.scipy.org/doc/numpy/reference/arrays.indexing.html
    for x in xrange(rank):
        sl=slice_[x]
        if isinstance(sl, int):
            if sl < 0:
                sl = shape[x] + slice_[x]

            _raise_index_error_int(sl, shape[x], x)
            slice_[x] = sl
        elif isinstance(sl, list):
            for i in xrange(len(sl)):
                if sl[i] < 0:
                    sl[i] = shape[x] + sl[i]

            _raise_index_error_list(sl, shape[x], x)
            slice_[x] = sl
        elif isinstance(sl, slice):
            sl_ = [sl.start, sl.stop, sl.step]
            if sl_[0] is not None and sl_[0] < 0:
                sl_[0] = shape[x] + sl_[0]

            if sl_[1] is not None and sl_[1] < 0:
                sl_[1] = shape[x] + sl_[1]

            if sl_[2] is not None:
                if sl_[2] < 0:
                    sl_[0], sl_[1], sl_[2] = sl_[1], sl_[0], -sl_[2]

#                # Fix the stop value based on the step
#                s=sl_[0] if sl_[0] is not None else 0
#                e=sl_[1] if sl_[1] is not None and sl_[1] <= shape[x] else shape[x]
#                m=xrange(s, e, sl_[2])[-1]
#                m += 1 # Stop is non-inclusive
#                sl_[1] = m

            # Reassign the slice
            slice_[x] = slice(*sl_)

            _raise_index_error_slice(slice_[x], shape[x], x)

    # Finally, make it a tuple
    return tuple(slice_)

def slice_shape(slice_, shape):
    """
    Returns a tuple containing the length of each dimension
    @param slice_       A slice, integer or list/tuple of indices
    @param shape        The shape of the data
    """
    # If shape is an integer, tuplize it
    if isinstance(shape, int):
        shape = (shape,)

    fixed_slice = fix_slice(slice_, shape)

    dim_lengths = []

    for s,shape in zip(fixed_slice, shape):
        if isinstance(s,slice):
            start, stop, stride = s.indices(shape)
            dim_len = int(math.ceil((stop - start) / float(stride)))
        elif isinstance(s, (list,tuple)):
            dim_len = len(s)
        elif isinstance(s, int):
            dim_len = 1
        else:
            raise TypeError('Unsupported slice method') # TODO: Better error message

        dim_lengths.append(dim_len)

    return tuple(dim_lengths)

def hash_any(value, hv=None):
    hv = hv or 0
    if value is None or isinstance(value, (str, unicode, int, long, float, bool)):
    #            log.debug('is primitive:  value=%s  hv=%s', value, hv)
        hv = hash(value) ^ hv
    elif isinstance(value, (list, tuple, set)):
    #            log.debug('is list/tuple/set:  value=%s  hv=%s', value, hv)
        for x in value:
            hv = hash_any(x, hv)
    elif isinstance(value, dict):
    #            log.debug('is dict:  value=%s  hv=%s', value, hv)
        for k,v in value.iteritems():
            hv = hash_any(k, hv)
            hv = hash_any(v, hv)
    elif isinstance(value, object):
    #            log.debug('is object:  value=%s  hv=%s', value, hv)
        hv = hash_any(value.__dict__, hv)

    return hv

<commit_msg>Adds checking for numpy scalars to utils.hash_any<commit_after>#!/usr/bin/env python

"""
@package
@file utils
@author Christopher Mueller
@brief
"""

import numpy as np
import uuid
import re
import math

def create_guid():
    """
    @retval Return global unique id string
    """
    # guids seem to be more readable if they are UPPERCASE
    return str(uuid.uuid4()).upper()

def is_guid(str_val):
    guid_match = r'^\w{8}-\w{4}-\w{4}-\w{4}-\w{12}'
    return re.match(guid_match, str_val) is not None

def prod(lst):
    import operator
    return reduce(operator.mul, lst, 1)

def is_valid_constraint(v):
    ret = False
    if isinstance(v, (slice, int)) or\
       (isinstance(v, (list,tuple)) and np.array([is_valid_constraint(e) for e in v]).all()):
        ret = True

    return ret

def find_nearest_index(seq, val):
    """
    Returns the index of the value in the array-like object arr nearest to val.

    seq is viewed as a numpy array using numpy.asanyarray()

    If seq contains duplicates, the first match is returned

    @param seq  The array-like object to search
    @param val  The value to search for
    @return     The index nearest to val
    """
    idx = np.abs(np.asanyarray(seq)-val).argmin()
    return idx

def find_nearest_value(seq, val):
    """
    Returns the value in the array-like object arr nearest to but not greater than val.

    seq is viewed as a numpy array using numpy.asanyarray()

    If seq contains duplicates, the first match is returned

    @param seq  The array-like object to search
    @param val  The value to search for
    @return     The value nearest to but not greater than val
    """
    a = np.asanyarray(seq)
    idx = find_nearest_index(a, val)
    fv = a.flat[idx]
    if val < fv:
        return a.flat[idx-1]
    else:
        return fv

def _raise_index_error_int(slice_, size, dim):
    if slice_ < 0:
        raise IndexError('On dimension {0}; index cannot be < 0: index => {0}'.format(dim, slice_))
    if slice_ >= size:
        raise IndexError('On dimension {0}; index cannot be >= the size: index => {1}, size => {2}'.format(dim, slice_, size))

def _raise_index_error_list(slice_, size, dim):
    last = -1
    for i in xrange(len(slice_)):
        c=slice_[i]
        if last >= c:
            raise IndexError('On dimension {0}; indices must be in increasing order and cannot be duplicated: list => {1}'.format(dim, slice_))
        last = c
        if slice_[i] >= size:
            raise IndexError('On dimension {0}; index {1} of list cannot be >= the size: list => {2}, size => {3}'.format(dim, i, slice_, size))

def _raise_index_error_slice(slice_, size, dim):
    if slice_.start is not None:
        if slice_.start < 0:
            raise IndexError('On dimension {0}; start index of slice cannot be < 0: slice => {1}, size => {2}'.format(dim, slice_, size))
        if slice_.start >= size:
            raise IndexError('On dimension {0}; start index of slice cannot be >= size: slice => {1}, size => {2}'.format(dim, slice_, size))
    if slice_.stop is not None:
        if slice_.start is None and slice_.stop == 0:
            raise IndexError('On dimension {0}; stop index of slice cannot be == 0 when the start index is None: slice => {1}, size => {2}'.format(dim, slice_, size))
        if slice_.stop < 0:
            raise IndexError('On dimension {0}; stop index of slice cannot be < 0: slice => {1}, size => {2}'.format(dim, slice_, size))
        # This case seems to be counter to how numpy functions - if a slice is longer than the shape, it's simply truncated to the appropriate size...
#        if slice_.stop > size:
#            raise IndexError('On dimension {0}; stop index of slice cannot be > size: slice => {1}, size => {2}'.format(dim, slice_, size))
    if slice_.start is not None and slice_.stop is not None:
        if slice_.start >= slice_.stop:
            raise IndexError('On dimension {0}; start index of slice cannot be >= stop index: slice => {1}'.format(dim, slice_))

def get_shape_from_slice(slice_, max_shp):
    shp=[]
    for i, s in enumerate(slice_):
        if isinstance(s, int):
            shp.append(1)
        elif isinstance(s, (list,tuple)):
            shp.append(len(s))
        elif isinstance(s, slice):
            st=min(s.stop, max_shp[i]) if s.stop is not None else max_shp[i]
            shp.append(len(range(*s.indices(st))))

    return tuple(shp)

def fix_slice(slice_, shape):
    # CBM: First swack - see this for more possible checks: http://code.google.com/p/netcdf4-python/source/browse/trunk/netCDF4_utils.py
    if not is_valid_constraint(slice_):
        raise SystemError('invalid constraint supplied: {0}'.format(slice_))

    # First, ensure we're working with a list so we can make edits...
    if not np.iterable(slice_):
        slice_ = [slice_,]
    elif not isinstance(slice_,list):
        slice_ = list(slice_)

    # If shape is an integer, tuplize it
    if isinstance(shape, int):
        shape = (shape,)

    # Then make sure it's the correct rank
    rank = len(shape)
    slen = len(slice_)
    if not slen == rank:
        if slen > rank:
            slice_ = slice_[:rank]
        else:
            for n in xrange(slen, rank):
                slice_.append(slice(None,None,None))

    # Next, deal with negative indices and check for IndexErrors
    # Logic for handling negative indices from: http://docs.scipy.org/doc/numpy/reference/arrays.indexing.html
    for x in xrange(rank):
        sl=slice_[x]
        if isinstance(sl, int):
            if sl < 0:
                sl = shape[x] + slice_[x]

            _raise_index_error_int(sl, shape[x], x)
            slice_[x] = sl
        elif isinstance(sl, list):
            for i in xrange(len(sl)):
                if sl[i] < 0:
                    sl[i] = shape[x] + sl[i]

            _raise_index_error_list(sl, shape[x], x)
            slice_[x] = sl
        elif isinstance(sl, slice):
            sl_ = [sl.start, sl.stop, sl.step]
            if sl_[0] is not None and sl_[0] < 0:
                sl_[0] = shape[x] + sl_[0]

            if sl_[1] is not None and sl_[1] < 0:
                sl_[1] = shape[x] + sl_[1]

            if sl_[2] is not None:
                if sl_[2] < 0:
                    sl_[0], sl_[1], sl_[2] = sl_[1], sl_[0], -sl_[2]

#                # Fix the stop value based on the step
#                s=sl_[0] if sl_[0] is not None else 0
#                e=sl_[1] if sl_[1] is not None and sl_[1] <= shape[x] else shape[x]
#                m=xrange(s, e, sl_[2])[-1]
#                m += 1 # Stop is non-inclusive
#                sl_[1] = m

            # Reassign the slice
            slice_[x] = slice(*sl_)

            _raise_index_error_slice(slice_[x], shape[x], x)

    # Finally, make it a tuple
    return tuple(slice_)

def slice_shape(slice_, shape):
    """
    Returns a tuple containing the length of each dimension
    @param slice_       A slice, integer or list/tuple of indices
    @param shape        The shape of the data
    """
    # If shape is an integer, tuplize it
    if isinstance(shape, int):
        shape = (shape,)

    fixed_slice = fix_slice(slice_, shape)

    dim_lengths = []

    for s,shape in zip(fixed_slice, shape):
        if isinstance(s,slice):
            start, stop, stride = s.indices(shape)
            dim_len = int(math.ceil((stop - start) / float(stride)))
        elif isinstance(s, (list,tuple)):
            dim_len = len(s)
        elif isinstance(s, int):
            dim_len = 1
        else:
            raise TypeError('Unsupported slice method') # TODO: Better error message

        dim_lengths.append(dim_len)

    return tuple(dim_lengths)

def hash_any(value, hv=None):
    hv = hv or 0
    if value is None or isinstance(value, (str, unicode, int, long, float, bool)) or np.isscalar(value):
    #            log.debug('is primitive:  value=%s  hv=%s', value, hv)
        hv = hash(value) ^ hv
    elif isinstance(value, (list, tuple, set)):
    #            log.debug('is list/tuple/set:  value=%s  hv=%s', value, hv)
        for x in value:
            hv = hash_any(x, hv)
    elif isinstance(value, dict):
    #            log.debug('is dict:  value=%s  hv=%s', value, hv)
        for k,v in value.iteritems():
            hv = hash_any(k, hv)
            hv = hash_any(v, hv)
    elif isinstance(value, object):
    #            log.debug('is object:  value=%s  hv=%s', value, hv)
        hv = hash_any(value.__dict__, hv)

    return hv

<|endoftext|>