<reponame>garethgeorge/pulse2percept
import numpy as np
import pytest
import numpy.testing as npt

from pulse2percept import models
from pulse2percept import stimuli
from pulse2percept import implants


class ValidBaseModel(models.BaseModel):
    """A class that implements all abstract methods of BaseModel"""

    def __init__(self, **kwargs):
        super(ValidBaseModel, self).__init__(**kwargs)
        # It must be allowed to set additional variables in the constructor:
        self._private = 0

    def _get_default_params(self):
        params = super(ValidBaseModel, self)._get_default_params()
        params.update({'valid': 1})
        return params

    def get_tissue_coords(self, xdva, ydva):
        return 290 * xdva, 290 * ydva

    def _predict_pixel_percept(self, xydva, img_stim, t=None):
        return 0

    def set_is_built(self):
        # This is not allowed outside constructor or ``build``:
        self._is_built = True


def test_BaseModel___init__():
    # Smoke test: Use default params:
    model = ValidBaseModel()
    npt.assert_almost_equal(model.valid, 1)
    # Set new value for existing param:
    model.valid = 2
    npt.assert_almost_equal(model.valid, 2)
    # However, creating new params outside the constructor is not allowed:
    with pytest.raises(AttributeError):
        model.newparam = 0
    # Passing parameters that are not in get_params() is not allowed:
    with pytest.raises(AttributeError):
        ValidBaseModel(newparam=0)
    # Technically, nobody stops you from calling model.key = value on other
    # variables, such as private variables (given you know they exist):
    model._private = 2
    npt.assert_almost_equal(model._private, 2)


def test_BaseModel_get_params():
    # We can overwrite default param values if they are in ``get_params``:
    model = ValidBaseModel(engine='serial')
    for key, value in model.get_params().items():
        if key in ('xrange', 'yrange', 'grid_type'):
            continue
        npt.assert_equal(getattr(model, key), value)
        setattr(model, key, 1234)
        npt.assert_equal(getattr(model, key), 1234)

        newmodel = ValidBaseModel(**{key: 1234})
        npt.assert_equal(getattr(newmodel, key), 1234)


def test_BaseModel_build():
    # Model must be built first thing
    model = ValidBaseModel(engine='serial')
    npt.assert_equal(model._is_built, False)
    model.build()
    npt.assert_equal(model._is_built, True)

    # Params passed to ``build`` must take effect:
    model = ValidBaseModel(engine='serial')
    model_params = model.get_params()
    for key, value in model_params.items():
        if isinstance(value, (int, float)):
            set_param = {key: 0.1234}
        elif isinstance(value, (list, set, tuple, np.ndarray)):
            set_param = {key: np.array([0, 0])}
        else:
            continue
        # Passing `set_param` during ``build`` must overwrite the earlier
        # value:
        model.build(**set_param)
        npt.assert_equal(getattr(model, key), set_param[key])


def test_BaseModel__is_built():
    # You cannot set `_is_built` outside the constructor or ``build``:
    model = ValidBaseModel(engine='serial')
    npt.assert_equal(model._is_built, False)
    with pytest.raises(AttributeError):
        model._is_built = True
    with pytest.raises(AttributeError):
        model.__is_built = True
    # After calling build, the flag should be set to True:
    model.build()
    npt.assert_equal(model._is_built, True)
    # You cannot set the flag in a new method you added, it has to be in
    # ``build``:
    with pytest.raises(AttributeError):
        model.set_is_built()


def test_BaseModel_predict_percept():
    img_stim = np.zeros(60)
    model = ValidBaseModel(engine='serial', xystep=5, xrange=(-30, 30),
                           yrange=(-20, 20))
    # Model must be built first:
    with pytest.raises(models.NotBuiltError):
        model.predict_percept(implants.ArgusII())

    # But then must pass through ``predict_percept`` just fine
    model.build()
    percept = model.predict_percept(implants.ArgusII(stim=img_stim))
    npt.assert_equal(percept.shape, (9, 13))
    npt.assert_almost_equal(percept, 0)

    # Requires ProsthesisSystem object:
    with pytest.raises(TypeError):
        model.predict_percept(img_stim)

    # None in, None out:
    npt.assert_equal(model.predict_percept(implants.ArgusII(stim=None)), None)

    # `img_stim` must have right size:
    for shape in [(2, 60), (59,), (2, 3, 4)]:
        with pytest.raises(ValueError):
            model.predict_percept(implants.ArgusII(stim=np.zeros(shape)))

    # Single-pixel percept:
    model = ValidBaseModel(engine='serial', xrange=(0.45, 0.45), yrange=(0, 0))
    model.build()
    percept = model.predict_percept(implants.ArgusII(stim=np.zeros(60)))
    npt.assert_equal(percept.shape, (1, 1))
    npt.assert_almost_equal(percept, 0)

import numpy as np
import pytest
import numpy.testing as npt

from pulse2percept import models
from pulse2percept import stimuli
from pulse2percept import implants


class ValidBaseModel(models.BaseModel):
    """A class that implements all abstract methods of BaseModel"""

    def __init__(self, **kwargs):
        super(ValidBaseModel, self).__init__(**kwargs)
        # It must be allowed to set additional variables in the constructor:
        self._private = 0

    def _get_default_params(self):
        params = super(ValidBaseModel, self)._get_default_params()
        params.update({'valid': 1})
        return params

    def get_tissue_coords(self, xdva, ydva):
        return 290 * xdva, 290 * ydva

    def _predict_pixel_percept(self, xydva, img_stim, t=None):
        return 0

    def set_is_built(self):
        # This is not allowed outside constructor or ``build``:
        self._is_built = True


def test_BaseModel___init__():
    # Smoke test: Use default params:
    model = ValidBaseModel()
    npt.assert_almost_equal(model.valid, 1)
    # Set new value for existing param:
    model.valid = 2
    npt.assert_almost_equal(model.valid, 2)
    # However, creating new params outside the constructor is not allowed:
    with pytest.raises(AttributeError):
        model.newparam = 0
    # Passing parameters that are not in get_params() is not allowed:
    with pytest.raises(AttributeError):
        ValidBaseModel(newparam=0)
    # Technically, nobody stops you from calling model.key = value on other
    # variables, such as private variables (given you know they exist):
    model._private = 2
    npt.assert_almost_equal(model._private, 2)


def test_BaseModel_get_params():
    # We can overwrite default param values if they are in ``get_params``:
    model = ValidBaseModel(engine='serial')
    for key, value in model.get_params().items():
        if key in ('xrange', 'yrange', 'grid_type'):
            continue
        npt.assert_equal(getattr(model, key), value)
        setattr(model, key, 1234)
        npt.assert_equal(getattr(model, key), 1234)

        newmodel = ValidBaseModel(**{key: 1234})
        npt.assert_equal(getattr(newmodel, key), 1234)


def test_BaseModel_build():
    # Model must be built first thing
    model = ValidBaseModel(engine='serial')
    npt.assert_equal(model._is_built, False)
    model.build()
    npt.assert_equal(model._is_built, True)

    # Params passed to ``build`` must take effect:
    model = ValidBaseModel(engine='serial')
    model_params = model.get_params()
    for key, value in model_params.items():
        if isinstance(value, (int, float)):
            set_param = {key: 0.1234}
        elif isinstance(value, (list, set, tuple, np.ndarray)):
            set_param = {key: np.array([0, 0])}
        else:
            continue
        # Passing `set_param` during ``build`` must overwrite the earlier
        # value:
        model.build(**set_param)
        npt.assert_equal(getattr(model, key), set_param[key])


def test_BaseModel__is_built():
    # You cannot set `_is_built` outside the constructor or ``build``:
    model = ValidBaseModel(engine='serial')
    npt.assert_equal(model._is_built, False)
    with pytest.raises(AttributeError):
        model._is_built = True
    with pytest.raises(AttributeError):
        model.__is_built = True
    # After calling build, the flag should be set to True:
    model.build()
    npt.assert_equal(model._is_built, True)
    # You cannot set the flag in a new method you added, it has to be in
    # ``build``:
    with pytest.raises(AttributeError):
        model.set_is_built()


def test_BaseModel_predict_percept():
    img_stim = np.zeros(60)
    model = ValidBaseModel(engine='serial', xystep=5, xrange=(-30, 30),
                           yrange=(-20, 20))
    # Model must be built first:
    with pytest.raises(models.NotBuiltError):
        model.predict_percept(implants.ArgusII())

    # But then must pass through ``predict_percept`` just fine
    model.build()
    percept = model.predict_percept(implants.ArgusII(stim=img_stim))
    npt.assert_equal(percept.shape, (9, 13))
    npt.assert_almost_equal(percept, 0)

    # Requires ProsthesisSystem object:
    with pytest.raises(TypeError):
        model.predict_percept(img_stim)

    # None in, None out:
    npt.assert_equal(model.predict_percept(implants.ArgusII(stim=None)), None)

    # `img_stim` must have right size:
    for shape in [(2, 60), (59,), (2, 3, 4)]:
        with pytest.raises(ValueError):
            model.predict_percept(implants.ArgusII(stim=np.zeros(shape)))

    # Single-pixel percept:
    model = ValidBaseModel(engine='serial', xrange=(0.45, 0.45), yrange=(0, 0))
    model.build()
    percept = model.predict_percept(implants.ArgusII(stim=np.zeros(60)))
    npt.assert_equal(percept.shape, (1, 1))
    npt.assert_almost_equal(percept, 0)
A class that implements all abstract methods of BaseModel # It must be allowed to set additional variables in the constructor: # This is not allowed outside constructor or ``build``: # Smoke test: Use default params: # Set new value for existing param: # However, creating new params outside the constructor is not allowed: # Passing parameters that are not in get_params() is not allowed: # Technically, nobody stops you from calling model.key = value on other # variables, such as private variables (given you know they exist): # We can overwrite default param values if they are in ``get_params``: # Model must be built first thing # Params passed to ``build`` must take effect: # Passing `set_param` during ``build`` must overwrite the earlier # value: # You cannot set `_is_built` outside the constructor or ``build``: # After calling build, the flag should be set to True: # You cannot set the flag in a new method you added, it has to be in # ``build``: # Model must be built first: # But then must pass through ``predict_percept`` just fine # Requires ProsthesisSystem object: # None in, None out: # `img_stim` must have right size: # Single-pixel percept: