-
Notifications
You must be signed in to change notification settings - Fork 21
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
consequences of gufe #260 change #666
Conversation
relies on this change: OpenFreeEnergy/gufe#260 this PR being the downstream consequences of this API change |
Codecov ReportAll modified and coverable lines are covered by tests ✅
Additional details and impacted files@@ Coverage Diff @@
## main #666 +/- ##
==========================================
- Coverage 91.33% 91.33% -0.01%
==========================================
Files 132 132
Lines 9328 9324 -4
==========================================
- Hits 8520 8516 -4
Misses 808 808
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overall this looks reasonable, although I'm not convinced on the method return change, in fact I think we should go more the other way and remove the "single mapping" error raising. This is especially because I know that Ivan wanted to re-use some of this tooling and maybe it's just overly restrictive for no reason?
@@ -243,6 +247,8 @@ def _validate_alchemical_components( | |||
logger.warning(wmsg) | |||
warnings.warn(wmsg) # TODO: remove this once logging is fixed | |||
|
|||
return mapping[0] # type: ignore |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The reason why this by default was not returning mapping[0] was so that a future protocol could re-use this method without enforcing the same behaviour. I.e. a requirement that only a single mapping is necessary is specific to this specific Protocol. If we're enforcing that specific protocols' behaviour then maybe we should just make thsi a class method?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
currently this function only allows a single mapping, so the function returns the only allowable input.
I'm not sure this code is sufficiently complex/interesting that it can't just be rewritten for new protocols, it's just a bunch of checks specific to this Protocol. Trying to make it general/useful for many different cases is probably more effort than just rewriting these checks. The choice of function/staticmethod is not that different?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd prefer to keep the function called _validate_X
purely for validation (i.e., a void
/ return None
function). I don't expect a function with that name to return something.
It's also better if it is reusable. Personally, I'd recommend splitting the warning check off, but that's out of scope for this PR. The stuff before that, which raises ValueError
s for bad mappings, is extremely reusable, and your typical PhD-student dev might forget some of those checks. Additionally, reusing code that generates error messages is extremely helpful for users searching for the error message (maybe we'll get it documented; even less likely that some random PhD student will make the effort).
I can change the function return back, but trying to share very simple functions like this feels like false-sharing where the cost of sharing is actually worse than just rewriting some simple code that is specific for each case. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My main thing is to turn the validate method back into something that only does validation. If, in OpenFreeEnergy/gufe#260, you take my recommendation to change mapping
-> mappings
, this PR will obviously need to update for that, too.
trying to share very simple functions like this feels like false-sharing where the cost of sharing is actually worse than just rewriting some simple code that is specific for each case.
I'm not sure how this has any analogy with false sharing. In that case, you're trying NOT to share a resource and are surprised by the fact that you are, and that leads to performance issues. If I'm missing a connection here, please clarify.
If someone doesn't want to use our validator, they don't need to. If they know it exists and it meets their needs, they use it. If they don't know it exists, then they write their own — that seems like the worst loss of time, and I'm not sure how having something potentially reusable in our makes that worse. It isn't even public API now, so there's no real issue here.
In any case, my argument is that the validator should only validate.
@@ -243,6 +247,8 @@ def _validate_alchemical_components( | |||
logger.warning(wmsg) | |||
warnings.warn(wmsg) # TODO: remove this once logging is fixed | |||
|
|||
return mapping[0] # type: ignore |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd prefer to keep the function called _validate_X
purely for validation (i.e., a void
/ return None
function). I don't expect a function with that name to return something.
It's also better if it is reusable. Personally, I'd recommend splitting the warning check off, but that's out of scope for this PR. The stuff before that, which raises ValueError
s for bad mappings, is extremely reusable, and your typical PhD-student dev might forget some of those checks. Additionally, reusing code that generates error messages is extremely helpful for users searching for the error message (maybe we'll get it documented; even less likely that some random PhD student will make the effort).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
blocking on upstream decision
@@ -521,7 +521,7 @@ def _create( | |||
self, | |||
stateA: ChemicalSystem, | |||
stateB: ChemicalSystem, | |||
mapping: Optional[Dict[str, gufe.ComponentMapping]] = None, | |||
mapping: list[gufe.ComponentMapping], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As discussed on the gufe PR, I would very much like this not to be how we do things going forward - it's very unintuitive from a Pythonic sense.
Hello @richardjgowers! Thanks for updating this PR. We checked the lines you've touched for PEP 8 issues, and found:
Comment last updated at 2024-02-07 10:34:48 UTC |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So the current approve in gufe 260 is to do Optional[mapping, list[mapping]], which is convenient from a user stand point.
My original take is that definitely "no mapping" == None (because that's what I'd expect in Python), but I don't have any strong opinions on list[mapping] vs Union[mapping, list[mapping]]. We should however make changes here to account for the single mapping case.
@@ -203,14 +203,13 @@ def _validate_alchemical_components( | |||
""" | |||
# Check mapping | |||
# For now we only allow for a single mapping, this will likely change | |||
if mapping is None or len(mapping.values()) > 1: | |||
if mapping is None or len(mapping) > 1: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What happens if you do len
on a single ComponentMapping?
6ddaac9
to
de909f6
Compare
all mappings to Protocol.create/Transformation.__init__ are now lists of mappings, not a dict
Just be safe and check against ComponentMapping
Just be safe and check against ComponentMapping also guard against len 0 list case
cf9d449
to
7a89fb2
Compare
# Conflicts: # openfe/protocols/openmm_afe/equil_solvation_afe_method.py # openfe/protocols/openmm_rfe/equil_rfe_methods.py # openfe/tests/protocols/test_openmm_equil_rfe_protocols.py
handle when mapping is single ComponentMapping not list
@dwhswenson - I believe your concerns have been addressed so I'll go ahead with a merge. If they haven't please do raise an issue and we can tackle further changes in a follow-up PR. |
Fix devtools for #666 changes
all mappings to Protocol.create/Transformation.init are now lists of mappings, not a dict
Developers certificate of origin