Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Deprecate CubeSlice shape property #101

Merged
merged 8 commits into from
Oct 3, 2018
Merged

Conversation

slobodan-ilic
Copy link
Contributor

  • Deprecation warning when shape property is used
  • Implement get_shape method, that uses prune argument
  • Unit tests

@coveralls
Copy link

coveralls commented Sep 26, 2018

Coverage Status

Coverage increased (+0.1%) to 98.468% when pulling c59ecbb on prune-slice-shape-160788065 into 20df047 on master.

@slobodan-ilic slobodan-ilic changed the title Deprecate shape property Deprecate CubeSlice shape property Sep 26, 2018
warnings.warn('Deprecated. Use `get_shape` instead.', DeprecationWarning)
return self.get_shape()

def get_shape(self, prune=False):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add docstring (PEP 257) describing interface and what a shape is.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. I've run the pylint on the entire file, should be better now...

warnings.warn(deprecation_msg, DeprecationWarning)
return self.get_shape()

def get_shape(self, prune=False):
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

memoize this.

"""Return the shape of the slice.

This property is anloguous to numpy's 'shape' property of ndarray. It
returns a tuple, returning the shape of the slice's 'as_array' method.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would always be preferable to avoid re-using the name of the method in its docstring. If a person doesn't know what "shape" means in this context, this docstring is going to make them work for it. So in this case, the second sentence might be better as: "It returns a tuple of ints, each representing the length of a cube dimension, in the order those dimensions appear in the cube."

I would add a blank line before the deprecated sentences. That topic is separate enough to warrant a distinct paragraph.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the thoughtful comment. This level of code review really means much to me.

I've addressed the comment. The first line of the docstring I copied from here, and modified it a little bit. The second sentence I took as you put it.

Please also check if the other modified docstring (of the method get_shape) is OK.

Copy link
Contributor

@scanny scanny left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, I left some feedback for whatever it's worth to you, but changes are not required, just some suggestions for possible improvements.

mock_sm_init.return_value = None

cs = CubeSlice({}, 0)
fake_axis = Mock()
cs.scale_means_margin(fake_axis)
assert mock_sm_margin.called_once_with(fake_axis)

def test_shape(self):
"""Test shape based on 'as_array' and pruning."""
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks like a good candidate for a parameterized test, maybe something like this:

def it_knows_its_shape(self, shape_fixture):  # ---or named `test_shape()` if you prefer---
    cube_slice, prune, expected_shape = shape_fixture
    shape = cube_slice.get_shape(prune=prune)
    assert shape == expected_value

@pytest.fixture(params=[
    (False, None, (3, 2)),
    (True, [[True, False], [True, False], [True, False]], (3,)),
    etc.
])
def shape_fixture(self, request, cube_):
    prune, mask_map, expected_value = request.param
    cube_.ndim = 2
    cube_.as_array.return_value = np.ma.masked_array(
        np.zeros((3, 2)), mask=np.array(mask_map) if mask_map else None
    )
    cube_slice = CubeSlice(cube_, 0)
    return cube_slice_, prune, expected_value

This isn't complete (or even correct) in every detail, but maybe gives you an idea. I recommend making the warning test a separate test method since its form and asserts are very different.

Using the fixture allows the test to be very clear and adding new cases is trivial and doesn't duplicate code.


This property is deprecated, use 'get_shape' instead. Pruning is not
supported (supported in 'get_shape').
"""
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sweet ❤️ :)

@@ -252,15 +266,65 @@ def is_double_mr(self):
return self.dim_types == ['multiple_response'] * 2

def scale_means(self, hs_dims=None, prune=False):
"""Calculate scale means of the CubeSlice."""
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a fine point, but I always use the word "Return" as the first word of the docstring for a method that returns a value. So something like "Return scale-means for this cube slice." This is the key aspect of the contract of such a method (the return value and type) and what the caller cares about most. Saying "Calculate" could just indicate a side-effect and leaves the reader to dig into the code (which often they won't have when just looking at the docs).

As an aside, in the case of a property, I leave the 'Return' word out, like "int count of foos in bar" instead of 'Return int count of foos in bar', since the semantics of a property are a value rather than a procedure.

You'll also need to say what scale-means are and what form you deliver them in. If that's not compact enough for the summary line, then in a body paragraph of the docstring. Even then, it's worth every effort not to repeat the method name in the summary because it provides no additional information. It could be something like """Return list containing scaled-mean for each slice column.""" or something and already starts to give more insight into the method contract.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done, thanks

- Deprecation warning when `shape` property is used
- Implement `get_shape` method, that uses `prune` argument
- Unit tests
- Improve docstrings
- Create parametrized test for checking 'get_shape' method
- Create separate test for deprecating 'shape' property
- Remove unittest, use pytest only
@crunchbot crunchbot merged commit c59ecbb into master Oct 3, 2018
@crunchbot crunchbot deleted the prune-slice-shape-160788065 branch October 3, 2018 16:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants