Skip to content

Base class for all metadata - #249

Open
rprospero wants to merge 7 commits into
refactor_24from
refactor_24_metadata_base_class
Open

rprospero wants to merge 7 commits into
refactor_24from
refactor_24_metadata_base_class

Conversation

@rprospero

Copy link
Copy Markdown
Contributor

The primary goal of this PR is to provide an abstract base class unifying the from_json, as_h5, and summary methods of the various Metadata component types, as mentioned in #244.

This additionally unlocked the following other options:

  • We can auto-generate most of the summaries via the introspect_summary and summarize_join methods that can now be shared between classes. This did necessitate small changes to the test files, since the different classes used to each have their own spacing convention, but are now all unified on four spaces and having the values aligned in the same column
  • Correct multiple typechecking issues in metadata.py
  • Change the Quantity class to use a NamedUnit instead of a Unit. This solves one of the type issues.
  • Standardize metadata.py on the ruff formatting

The individual commits should all type-check, so I am happy to re-submit this PR as a subset of these features if it is too large on its own or any of these changes aren't desired.

Closes #244

codescene-access[bot]

This comment was marked as outdated.

@codescene-access codescene-access Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

No quality gates enabled for this code.

See analysis details in CodeScene

Quality Gate Profile: Custom Configuration
Install CodeScene MCP: safeguard and uplift AI-generated code. Catch issues early with our IDE extension and CLI tool.

@jamescrake-merani jamescrake-merani left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Thanks Adam, this I think is definitely an improvement. I just have a few comments I'd like you to consider before I approve.

self,
value: QuantityType,
units: Unit,
units: NamedUnit,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Why has this been changed? My original understanding was that this was kept as Unit because the Quantity doesn't need to know the name of the Unit; it just needs to know details of the Unit to do the conversions.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I just read your summary message again, and it looks like you did this to solve an error from a type checker. What was the error exactly?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I've given this a second look and I can get around the typing issue without changing the Quantity class, so I've rolled back this change for now. The new correction can be seen in line 485 of metadata.py.

That said, there's part of me that does feel that Quantity should require a NamedUnit. From just a science perspective, if a quantity has a unit, but you can't tell me the unit, it feels pretty identical to their not being a unit. Still, I think that's a large debate that shouldn't be skipped.

if result := known_mistake(unit_str):
return result
try:
import sasdata.quantities.units as units

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Is there a reason a deferred import is needed here? If so, it might be good to add a comment explaining why.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Good catch. I've moved the import back up to the top. I briefly considered just importing none from sasdata.quantities.units, but having both none and None be valid values in the file seemed like a disaster waiting to happen.

Comment thread sasdata/metadata.py
@abc.abstractmethod
def from_json(cls, obj: dict) -> Self | None:
"""Load this metadata from a JSON dict"""
return None

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

It might be better to raise a NotImplementedError for the abstract methods. This would mean that, in the case a subclass doesn't implement the method as it should, an error occurs rather than returning None.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Agreed

Comment thread sasdata/metadata.py
return str(x)

def _pretty_field(self, x: str) -> str:
match x:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

It might be nicer to have a dictionary here instead of a match statement. I just did something similar today on the plotting refactor refactor (SasView/sasview#4166).

tab_name_dict = {0: "Data", 1: "Fit"}


def tab_name(i: int) -> str:
    return tab_name_dict.get(i, "Unknown")

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I get a little too happy with match statements. The dict is shorter.

This branch has not been deployed

No deployments
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.

2 participants