Skip to content

Do not allow an empty instance of DiffractionObject - require xarrays yarrays xtype #228

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

Merged
merged 33 commits into from
Dec 16, 2024

Conversation

bobleesj
Copy link
Contributor

@bobleesj bobleesj commented Dec 14, 2024

Closes #227

Copy link

codecov bot commented Dec 14, 2024

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 100.00%. Comparing base (7b6ee2e) to head (ba4b985).
Report is 36 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff            @@
##              main      #228   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files            8         8           
  Lines          372       380    +8     
=========================================
+ Hits           372       380    +8     
Files with missing lines Coverage Δ
tests/conftest.py 100.00% <100.00%> (ø)
tests/test_diffraction_objects.py 100.00% <100.00%> (ø)


def input_data(self, xarray, yarray, xtype, wavelength, scat_quantity="", name="", metadata={}):
"""
Insert a new scattering quantity into the scattering object.
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Improved docstrings, previous version:

        f"""
        insert a new scattering quantity into the scattering object
        Parameters
        ----------
        xarray array-like of floats
          the independent variable array
        yarray array-like of floats
          the dependent variable array
        xtype string
          the type of quantity for the independent variable from {*XQUANTITIES, }
        metadata, scat_quantity, name and wavelength are optional.  They have the same
        meaning as in the constructor. Values will only be overwritten if non-empty values are passed.
        Returns
        -------
        Nothing.  Updates the object in place.
        """

Copy link
Contributor

Choose a reason for hiding this comment

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

If we make it private we may want to move the docstring to the constructor? Also, then change "insert a new scattering object blah blah, to instantiate a new scattering object or sthg.

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

Copy link
Contributor

@sbillinge sbillinge left a comment

Choose a reason for hiding this comment

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

Please see inline. We may want to check it is ok for us to have things like empty string details instead of None that converts to empty string


def input_data(self, xarray, yarray, xtype, wavelength, scat_quantity="", name="", metadata={}):
"""
Insert a new scattering quantity into the scattering object.
Copy link
Contributor

Choose a reason for hiding this comment

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

If we make it private we may want to move the docstring to the constructor? Also, then change "insert a new scattering object blah blah, to instantiate a new scattering object or sthg.

self.input_data(xarray, yarray, xtype)
self._input_xtype = xtype
self._set_xarrays(xarray, xtype)
self._all_arrays[:, 0] = yarray
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 be cleaner of this was moved into _set_arrays unless there was a reason not to do that because it is reused somewhere or something

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

@@ -41,17 +36,17 @@
{
"name": "something",
"scat_quantity": "",
"wavelength": None,
"xtype": "",
"wavelength": 0.71,
Copy link
Contributor

Choose a reason for hiding this comment

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

Return wavelengths back to None or absent to test that behavior.

@@ -241,40 +236,6 @@ def test_dump(tmp_path, mocker):


tc_params = [
(
{},
Copy link
Contributor

Choose a reason for hiding this comment

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

Where are these things now getting tested?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

pls see test_init_invalid_args below

Copy link
Contributor

Choose a reason for hiding this comment

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

but I think these are valid aren't they?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@sbillinge I think these aren't valid since we DiffractionObject requires x, y, and xtype (current PR)

@bobleesj
Copy link
Contributor Author

bobleesj commented Dec 14, 2024

Please see inline. We may want to check it is ok for us to have things like empty string details instead of None that converts to empty string

@sbillinge Before making PRs, when would be beneficial to have none for xtype or scat_quantity?

My understanding is that we usually want to pass typed variables so that typecasting can be minimal.

Extra comment:

I can see that having wavelength=none makes sense since we don't want a float value associated when it's not provided.

@sbillinge
Copy link
Contributor

Please see inline. We may want to check it is ok for us to have things like empty string details instead of None that converts to empty string

@sbillinge Before making PRs, when would be beneficial to have none for xtype or scat_quantity?

I can't think of a case where we want none for xtype. I think we require this, right? For scat_quantity, the tradeoff is between making these easier to use (and therefore encouraging adoption) vs. making them stricter so we collect better metadata. I think leaning in the direction of adoption may be a good starting point for that (though if they are adopted, we may regret that later). That is the UC for a None default for scat_quantity: lazy users....

My understanding is that we usually want to pass typed variables so that typecasting can be minimal.

The issue is with setting mutable objects as defaults. In that case you should pass None and then you have logic like, if thing is None: thing = [] or whatever. I was being a bit too conservative about the empty strings. i was thinking they are mutable since they can act like lists, but I checked and they are not subject to this issue. So we could directly set empty strings (and of course floats and ints) as defaults.

Extra comment:

I can see that having wavelength=none makes sense since we don't want a float value associated when it's not provided.

yes, in this case None is different from 0. We want None here.

@bobleesj bobleesj changed the title Do not allow an empty instance of DiffractionObject Do not allow an empty instance of DiffractionObject - require xarrays yarrays xtype Dec 14, 2024
self.metadata = metadata
self.name = name
self._input_xtype = xtype
self._set_arrays(xarray, xtype, yarray)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

as discussed - private func

Copy link
Contributor Author

@bobleesj bobleesj left a comment

Choose a reason for hiding this comment

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

@sbillinge This is ready for review - pls see in-line comments..

@bobleesj bobleesj marked this pull request as ready for review December 14, 2024 19:01
@bobleesj
Copy link
Contributor Author

(Just added news)

Copy link
Contributor Author

@bobleesj bobleesj left a comment

Choose a reason for hiding this comment

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

@sbillinge re-revisiting after resolving a conftest.py conflict. and ready for review.

Copy link
Contributor

@sbillinge sbillinge left a comment

Choose a reason for hiding this comment

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

I reviewed this yesterday or so but it looks as if I forgot to submit the review.....sorry.

>>> x = np.array([0.12, 0.24, 0.31, 0.4]) # independent variable (e.g., q)
>>> y = np.array([10, 20, 40, 60]) # intensity values
>>> metadata = {
... "package_info": {"version": "3.6.0"}
Copy link
Contributor

Choose a reason for hiding this comment

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

this could only have been come up with by a programmer. Could we instead have an example of what we are after from materials scientists. Model some good behavior. Something like metadata = {'sample': "rock salt from the beach", "composition": "NaCl", "temperature": "300 K,", "experimenters": "Phill, Sally" }

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Screenshot 2024-12-15 at 9 12 12 PM

Done

array = self.on_xtype(xtype)[0]
if len(array) == 0:
raise ValueError(f"The '{xtype}' array is empty. Please ensure it is initialized.")
i = (np.abs(array - value)).argmin()
return i

def _set_xarrays(self, xarray, xtype):
def _set_arrays(self, xarray, xtype, yarray):
Copy link
Contributor

Choose a reason for hiding this comment

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

maybe we should stay consistent...x, y, xtype order?

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

@@ -241,40 +236,6 @@ def test_dump(tmp_path, mocker):


tc_params = [
(
{},
Copy link
Contributor

Choose a reason for hiding this comment

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

but I think these are valid aren't they?

@bobleesj
Copy link
Contributor Author

@sbillinge ready for review!

@sbillinge
Copy link
Contributor

There is a lot of good stuff on here and this is really getting wrestled into shape in my mind so I want to merge this (and will). There were two things left to do that I will mae issues for. Thanks for your work on this. It is really great!

@sbillinge sbillinge merged commit da32ae3 into diffpy:main Dec 16, 2024
2 of 3 checks passed
@bobleesj bobleesj deleted the no-empty-object branch December 16, 2024 11:24
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.

Do not allow an empty instance of DiffractionObject - init requires xarray, yarray, xtype
2 participants