Skip to content

Commit

Permalink
Update preprocessing, rename the first argument of _validate_ndarray …
Browse files Browse the repository at this point in the history
…from input to array and add a TODO in resampling
  • Loading branch information
DevinCrowley committed Aug 22, 2019
1 parent 3b7d93d commit 62e45ba
Show file tree
Hide file tree
Showing 4 changed files with 51 additions and 48 deletions.
6 changes: 3 additions & 3 deletions ardent/preprocessing/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,6 @@ def preprocess(data:(np.ndarray, list), processes:list):
raise ValueError(f"Process {process} not recognized.\n"
f"Recognized processes: {preprocessing_functions}.")

# Return in a form appropriate to what was passed in.
# i.e. list in, list out, np.ndarray in, np.ndarray out, empty list in, None out.
return data if len(data) > 1 else data[0] if len(data) == 1 else None
# Return in a form appropriate to what was passed in,
# i.e. list in, list out, np.ndarray in, np.ndarray out.
return data[0] if isinstance(data, list) and len(data) == 1 else data
5 changes: 4 additions & 1 deletion ardent/preprocessing/resampling.py
Original file line number Diff line number Diff line change
Expand Up @@ -382,4 +382,7 @@ def change_resolution_by(image, xyz_scales, xyz_resolution=1,
# TODO: reconcile use of scipy.interpolate.interpn vs scipy.misc.resize & skimage.transform.downscale_local_mean.

# TODO: isolate negative scale conversion into its own function.
# TODO: merge necessary new_shape transformations etc. into _resample.
# TODO: merge necessary new_shape transformations etc. into _resample.

# TODO: recreate bug from quick_demo and test it into oblivion.
# TODO: implement to_this_shape user-level resampling function.
48 changes: 24 additions & 24 deletions ardent/utilities.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,23 +56,23 @@ def _validate_scalar_to_multi(value, size=3, dtype=float):
return value


def _validate_ndarray(input, minimum_ndim=0, required_ndim=None, dtype=None,
def _validate_ndarray(array, minimum_ndim=0, required_ndim=None, dtype=None,
forbid_object_dtype=True, broadcast_to_shape=None):
"""Cast (a copy of) input to a np.ndarray if possible and return it
"""Cast (a copy of) array to a np.ndarray if possible and return it
unless it is noncompliant with minimum_ndim, required_ndim, and dtype.
Note:
If required_ndim is None, _validate_ndarray will accept any object.
If it is possible to cast to dtype, otherwise an exception is raised.
If np.array(input).ndim == 0 and required_ndim == 1, input will be upcast to ndim 1.
If np.array(array).ndim == 0 and required_ndim == 1, array will be upcast to ndim 1.
If forbid_object_dtype == True and the dtype is object, an exception is raised
unless object is the dtype.
If a shape is provided to broadcast_to_shape, unless noncompliance is found with
required_ndim, input is broadcasted to that shape."""
required_ndim, array is broadcasted to that shape."""

# Verify arguments.

Expand All @@ -99,41 +99,41 @@ def _validate_ndarray(input, minimum_ndim=0, required_ndim=None, dtype=None,
raise TypeError(f"dtype must be either None or a valid type."
f"type(dtype): {type(dtype)}.")

# Validate input.
# Validate array.

# Cast input to np.ndarray.
# Cast array to np.ndarray.
# Validate compliance with dtype.
try:
input = np.array(input, dtype) # Side effect: breaks alias.
array = np.array(array, dtype) # Side effect: breaks alias.
except TypeError:
raise TypeError(f"input is of a type that is incompatible with dtype.\n"
f"type(input): {type(input)}, dtype: {dtype}.")
raise TypeError(f"array is of a type that is incompatible with dtype.\n"
f"type(array): {type(array)}, dtype: {dtype}.")
except ValueError:
raise ValueError(f"input has a value that is incompatible with dtype.\n"
f"input: {input}, \ntype(input): {type(input)}, dtype: {dtype}.")
raise ValueError(f"array has a value that is incompatible with dtype.\n"
f"array: {array}, \ntype(array): {type(array)}, dtype: {dtype}.")

# Verify compliance with forbid_object_dtype.
if forbid_object_dtype:
if input.dtype == object and dtype != object:
raise TypeError(f"Casting input to a np.ndarray produces an array of dtype object while forbid_object_dtype == True and dtype != object.")
if array.dtype == object and dtype != object:
raise TypeError(f"Casting array to a np.ndarray produces an array of dtype object while forbid_object_dtype == True and dtype != object.")

# Validate compliance with required_ndim.
if required_ndim is not None and input.ndim != required_ndim:
if required_ndim is not None and array.ndim != required_ndim:
# Upcast from ndim 0 to ndim 1 if appropriate.
if input.ndim == 0 and required_ndim == 1:
input = np.array([input])
if array.ndim == 0 and required_ndim == 1:
array = np.array([array])
else:
raise ValueError(f"If required_ndim is not None, input.ndim must equal it unless input.ndim == 0 and required_ndin == 1.\n"
f"input.ndim: {input.ndim}, required_ndim: {required_ndim}.")
raise ValueError(f"If required_ndim is not None, array.ndim must equal it unless array.ndim == 0 and required_ndin == 1.\n"
f"array.ndim: {array.ndim}, required_ndim: {required_ndim}.")

# Verify compliance with minimum_ndim.
if input.ndim < minimum_ndim:
raise ValueError(f"input.ndim must be at least equal to minimum_ndim."
f"input.ndim: {input.ndim}, minimum_ndim: {minimum_ndim}.")
if array.ndim < minimum_ndim:
raise ValueError(f"array.ndim must be at least equal to minimum_ndim."
f"array.ndim: {array.ndim}, minimum_ndim: {minimum_ndim}.")

# Broadcast input if appropriate.
# Broadcast array if appropriate.
if broadcast_to_shape is not None:
input = np.copy(np.broadcast_to(array=input, shape=broadcast_to_shape))
array = np.copy(np.broadcast_to(array=array, shape=broadcast_to_shape))

return input
return array

40 changes: 20 additions & 20 deletions tests/test_utilities.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,85 +87,85 @@ def test__validate_ndarray():

# Test proper use.

kwargs = dict(input=np.arange(3, dtype=int), dtype=float)
kwargs = dict(array=np.arange(3, dtype=int), dtype=float)
correct_output = np.arange(3, dtype=float)
assert np.array_equal(_validate_ndarray(**kwargs), correct_output)

kwargs = dict(input=[[0,1,2], [3,4,5]], dtype=float)
kwargs = dict(array=[[0,1,2], [3,4,5]], dtype=float)
correct_output = np.arange(2*3, dtype=float).reshape(2,3)
assert np.array_equal(_validate_ndarray(**kwargs), correct_output)

kwargs = dict(input=np.array([0,1,2]), broadcast_to_shape=(2,3))
kwargs = dict(array=np.array([0,1,2]), broadcast_to_shape=(2,3))
correct_output = np.array([[0,1,2], [0,1,2]])
assert np.array_equal(_validate_ndarray(**kwargs), correct_output)

kwargs = dict(input=np.array(7), required_ndim=1)
kwargs = dict(array=np.array(7), required_ndim=1)
correct_output = np.array([7])
assert np.array_equal(_validate_ndarray(**kwargs), correct_output)

# Test improper use.

# Validate arguments.

kwargs = dict(input=np.arange(3), minimum_ndim=1.5)
kwargs = dict(array=np.arange(3), minimum_ndim=1.5)
expected_exception = TypeError
match = "minimum_ndim must be of type int."
with pytest.raises(expected_exception, match=match):
_validate_ndarray(**kwargs)

kwargs = dict(input=np.arange(3), minimum_ndim=-1)
kwargs = dict(array=np.arange(3), minimum_ndim=-1)
expected_exception = ValueError
match = "minimum_ndim must be non-negative."
with pytest.raises(expected_exception, match=match):
_validate_ndarray(**kwargs)

kwargs = dict(input=np.arange(3), required_ndim=1.5)
kwargs = dict(array=np.arange(3), required_ndim=1.5)
expected_exception = TypeError
match = "required_ndim must be either None or of type int."
with pytest.raises(expected_exception, match=match):
_validate_ndarray(**kwargs)

kwargs = dict(input=np.arange(3), required_ndim=-1)
kwargs = dict(array=np.arange(3), required_ndim=-1)
expected_exception = ValueError
match = "required_ndim must be non-negative."
with pytest.raises(expected_exception, match=match):
_validate_ndarray(**kwargs)

kwargs = dict(input=np.arange(3), dtype="not of type type")
kwargs = dict(array=np.arange(3), dtype="not of type type")
expected_exception = TypeError
match = "dtype must be either None or a valid type."
with pytest.raises(expected_exception, match=match):
_validate_ndarray(**kwargs)

# Validate input.
# Validate array.

kwargs = dict(input=np.array(print), dtype=int)
kwargs = dict(array=np.array(print), dtype=int)
expected_exception = TypeError
match = "input is of a type that is incompatible with dtype."
match = "array is of a type that is incompatible with dtype."
with pytest.raises(expected_exception, match=match):
_validate_ndarray(**kwargs)

kwargs = dict(input=np.array('string that is not an int'), dtype=int)
kwargs = dict(array=np.array('string that is not an int'), dtype=int)
expected_exception = ValueError
match = "input has a value that is incompatible with dtype."
match = "array has a value that is incompatible with dtype."
with pytest.raises(expected_exception, match=match):
_validate_ndarray(**kwargs)

kwargs = dict(input=np.array([[], 1]), dtype=None, forbid_object_dtype=True)
kwargs = dict(array=np.array([[], 1]), dtype=None, forbid_object_dtype=True)
expected_exception = TypeError
match = "Casting input to a np.ndarray produces an array of dtype object while forbid_object_dtype == True and dtype != object."
match = "Casting array to a np.ndarray produces an array of dtype object while forbid_object_dtype == True and dtype != object."
with pytest.raises(expected_exception, match=match):
_validate_ndarray(**kwargs)

kwargs = dict(input=np.arange(3), required_ndim=2)
kwargs = dict(array=np.arange(3), required_ndim=2)
expected_exception = ValueError
match = "If required_ndim is not None, input.ndim must equal it unless input.ndim == 0 and required_ndin == 1."
match = "If required_ndim is not None, array.ndim must equal it unless array.ndim == 0 and required_ndin == 1."
with pytest.raises(expected_exception, match=match):
_validate_ndarray(**kwargs)

kwargs = dict(input=np.arange(3), minimum_ndim=2)
kwargs = dict(array=np.arange(3), minimum_ndim=2)
expected_exception = ValueError
match = "input.ndim must be at least equal to minimum_ndim."
match = "array.ndim must be at least equal to minimum_ndim."
with pytest.raises(expected_exception, match=match):
_validate_ndarray(**kwargs)

Expand Down

0 comments on commit 62e45ba

Please sign in to comment.