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

Make GenericParameters return optional instead of empty defaults on non-existant keys #580

Merged
merged 11 commits into from
Jun 6, 2024

Conversation

tmadlener
Copy link
Collaborator

@tmadlener tmadlener commented Apr 10, 2024

BEGINRELEASENOTES

  • Make the GenericParameters return std::optional on non-existant keys instead of empty defaults. This allows to differentiate between empty (but set) and unset parameters, as the default value could actually be a valid parameter value for some types (e.g. integers or floats).
    • Rename the setValue and getValue functions to just set and get. This is also a breaking change, but as far as we are aware the GenericParameters are only used internally in podio.
  • Make the Frame::getParameter also return this std::optional. This is a breaking change that might require adaptation of existing code

ENDRELEASENOTES

Fixes #576

The following PRs make this introduction work transparently and need to be merged first to not break the nightlies

include/podio/Frame.h Outdated Show resolved Hide resolved
@m-fila
Copy link
Contributor

m-fila commented Apr 19, 2024

I think getValue is an unintuitive name for a method returning optional instead of "value".
Code like parameter.GetValue<int>("foo").has_value() reads a bit awkward

@tmadlener
Copy link
Collaborator Author

Since we are breaking interfaces in any case I don't mind different names. That would in principle allow us to properly deprecate getValue as it is. On the other hand GenericParameters is mainly used internally, so we could probably also just use new names without deprecation.

Copy link
Contributor

@m-fila m-fila left a comment

Choose a reason for hiding this comment

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

podio/include/podio/Frame.h

Lines 290 to 298 in 5e95c36

/// Retrieve all parameters stored in this Frame.
///
/// This is mainly intended for I/O purposes and we encourage to use the Frame
/// functionality of getParameters or getParameterKeys in general.
///
/// @returns The internally used GenericParameters
inline const podio::GenericParameters& getParameters() const {
return m_self->parameters();
}

I think the comment here should recommend usage of getParameter instead of getParameters

include/podio/Frame.h Outdated Show resolved Hide resolved
@hegner
Copy link
Collaborator

hegner commented May 14, 2024

@tmadlener - ping. What's the status?

@tmadlener
Copy link
Collaborator Author

Currently testing what is breaking downstream (and then fixing that if necessary)

@tmadlener
Copy link
Collaborator Author

I think getValue is an unintuitive name for a method returning optional instead of "value". Code like parameter.GetValue<int>("foo").has_value() reads a bit awkward

I have changed this to get as we are breaking things in any case

if len(par_value) == 1:
return par_value[0]
return list(par_value)
return list(deepcopy(par_value))
Copy link
Member

Choose a reason for hiding this comment

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

Why is this needed? Do the values disappear if the frame is deleted?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

They will definitely disappear if the Frame is gone. but in this case I think it's also something related to std::optional and how it combines with cppyy. I added it to fix tests, but let me check whether it's truly necessary.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

It seems to be interaction between std::optional and cppyy. Without the deepcopy, I run into the following in the tests:

130: ======================================================================
130: ERROR: test_frame_parameters (test_Frame.FrameReadTest)
130: Check that all expected parameters are available.
130: ----------------------------------------------------------------------
130: Traceback (most recent call last):
130:   File "/home/tmadlener/work/AIDASoft/podio/python/podio/test_Frame.py", line 192, in test_frame_parameters
130:     self.assertEqual(
130:   File "/home/tmadlener/work/.spack/spackages/python/3.10.13/skylake-ubuntu22.04-gcc12.3.0/jsngvl3/lib/python3.10/unittest/case.py", line 845, in assertEqual
130:     assertion_func(first, second, msg=msg)
130:   File "/home/tmadlener/work/.spack/spackages/python/3.10.13/skylake-ubuntu22.04-gcc12.3.0/jsngvl3/lib/python3.10/unittest/case.py", line 1051, in assertListEqual
130:     self.assertSequenceEqual(list1, list2, msg, seq_type=list)
130:   File "/home/tmadlener/work/.spack/spackages/python/3.10.13/skylake-ubuntu22.04-gcc12.3.0/jsngvl3/lib/python3.10/unittest/case.py", line 976, in assertSequenceEqual
130:     if seq1 == seq2:
130: SystemError: Negative size passed to PyUnicode_FromStringAndSize

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I think the problem is that the par_value (or it's underlying storage) goes out of scope without the deepcopy. Previously the getParameter returned a const& so it was kept alive by the underlying frame, so no deepcopy was necessary.

@@ -8,7 +8,7 @@ project(podio)
#--- Version -------------------------------------------------------------------
SET( ${PROJECT_NAME}_VERSION_MAJOR 0 )
SET( ${PROJECT_NAME}_VERSION_MINOR 99 )
SET( ${PROJECT_NAME}_VERSION_PATCH 0 )
SET( ${PROJECT_NAME}_VERSION_PATCH 99 )
Copy link
Member

Choose a reason for hiding this comment

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

So this is the last version before 1.0 😃

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

:D I would hope so. However, the main reason for this is that setting this to 99 would in principle allow us to still have patch releases, while still having pre-processor checks only compare >0.99 effectively.

In principle we could consider doing this by default after tagging a release to make it easier to detect development builds.

@tmadlener tmadlener force-pushed the generic-params-ret-optional branch from f8a8475 to c08a433 Compare May 23, 2024 08:17
@tmadlener
Copy link
Collaborator Author

@Zehvogel a quick heads up:

  • Rename the setValue and getValue functions to just set and get. This is also a breaking change, but as far as we are aware the GenericParameters are only used internally in podio.

This bit here will require some changes to your RDataFrame code where you directly talk to the PARAMETERS branch, mainly

- df = df.Define("xsec_fb", "PARAMETERS.getValue<float>(\"crossSection\")")
+ df = df.Define("xsec_fb", "PARAMETERS.get<float>(\"crossSection\")")

@tmadlener tmadlener merged commit 1b80735 into AIDASoft:master Jun 6, 2024
18 checks passed
@tmadlener tmadlener deleted the generic-params-ret-optional branch June 6, 2024 08:27
@Zehvogel
Copy link
Contributor

This bit here will require some changes to your RDataFrame code where you directly talk to the PARAMETERS branch, mainly

actually needed a

- df = df.Define("xsec_fb", "PARAMETERS.getValue<float>(\"crossSection\")")
+ df = df.Define("xsec_fb", "*PARAMETERS.get<float>(\"crossSection\")")

(or something intelligent :))

@tmadlener
Copy link
Collaborator Author

Ah yes, because it now also returns a std::optional. so, either operator* (as in your diff) or .value() will get you the actual value and not the optional).

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.

GenericParameters should not return a default constructed / empty value if key is not present
5 participants