[v7r2] Helper functions to make working with errors easier#5145
Conversation
|
As already discussed, I like the idea :-) |
|
The idea here is smart certainly. But I do not like it. Packing the code in fewer lines does not mean it is more readable, especially for people who are not deeply involved in the development and should quickly guess the logic of what they read. The example of the ComponentInstaller is very good. The longer version is readable as just a text. The shorter version requires extra non-trivial knowledge about the decorator and the unwrap function semantics. Yes, the second one is shorter but this is the only added value. Is it really a value ? |
|
I would find it much preferable if I could write fewer I think the Maybe also |
|
This discussion happens once in a while :) . May be I am just in habit, but I like the necessity when writing code to do the check if result['OK'] at all the levels. If you think it should be handled upper in the stack, just return it. But you do that consciously and do not rely on some general mechanism. The length of the code IS NOT a problem itself if takes LESS time to understand what goes on. That's why many smart python features allowing to reduce in one line otherwise multi-line code is smart but is actually worse, less clear in the end especially if the code is to be read by your colleagues (or by yourself later on). The constructs like in this PR are creating new language constructs which only have value if everybody speaks this language otherwise we get a Babylonian problem. |
except (pun intended?) you can't just return it, you first need to check it. |
|
I do think the length of the code is a problem. You get lost in the Had we used exceptions from the beginning, there would be no need for this new functions. What Chris proposes here allows for a backward compatible and smooth transition, although the names could be improved. Now, when it comes to code complexity, I find it much more difficult to understand what DIRAC does under the hood than this :-D |
|
Do you want to say that we are transiting from functions returning status to functions throwing exceptions changing completely the paradigm ? I am afraid this will be another project then. |
What do you mean ? |
|
In response to @andresailer:
I'm divided here. Having used this style for a while I find the length of the "unwrap" function to be annoying and forces the code on to multiple lines, especially in combination with DIRAC's tenancy to have fairly long/repetitive class and function names, e.g. fileCounts = returnValueOrRaise(TransformationClient().getTransformationFilesCount(transID, "Status"))
fileCounts = unwrap(TransformationClient().getTransformationFilesCount(transID, "Status"))In my code I've been using For the decorator I think I prefer |
|
And in response to @atsareg:
DIRAC has new language constructs by trying to pretend Python doesn't use exceptions for this and I've never seen anything like This
I agree, but if the code I'm interested in doesn't fit in my screen height it's a problem as it's much harder to maintain the mental model of what it's doing. Of course you have over a decade of looking at DIRAC's way of doing things so anything else is going to look "wrong" to you. Most of the time DIRAC's way results in you being distracted by error handling which doesn't even work properly because you also need to also have the
Despite everything above about why
|
|
First, the goal of the DIRAC project is not to be Pythonic but rather deliver the functionality it is intended for. However, coding in DIRAC should be of course as efficient as possible for most of the developers. |
DIRAC isn't a project written and used by a single person so the reason to be Pythonic is to make it easier for contributors. Many people that contribute are inexperienced students that benefit much more if they see best practices instead of DIRAC's own weird way of doing things. People literally get rejected during job interview processes for this kind of "bad style". (It's arbitrary and unfair but there is nothing we can do about it.)
Absolutely! I've done this in the context of a PR as the change is so small that I think the idea is better communicated with code. I'm completely open to discussing any technical issues with the approach or better ideas that others may have. |
|
This is kind of a "coffee discussion" that routinely comes up. I have mixed feelings (maybe because I am neither part of the first group of DIRAC developers, nor of the last one). On one side, I like exceptions, and their handling. On the other, I would not so much like to code in a "mixed world". With the years I have just accepted that this is how DIRAC is coded and I adapt to it. I agree that:
|
I should probably say that I'm somewhat down-playing the potential impact of this. I see this as having the potential to significantly improve the design of DIRAC without causing any migration headaches. For example when reviewing #5149 I couldn't help think that this could have been much easier to understand with my proposal: def writeToTokenFile(tokenContents, fileName=False):
""" Write a token string to file
:param str tokenContents: token as string
:param str fileName: filename to dump to
:return: S_OK(str)/S_ERROR()
"""
if not fileName:
try:
fd, tokenLocation = tempfile.mkstemp()
os.close(fd)
except IOError:
return S_ERROR(DErrno.ECTMPF)
fileName = tokenLocation
try:
with open(fileName, 'wb') as fd:
fd.write(tokenContents)
except Exception as e:
return S_ERROR(DErrno.EWF, " %s: %s" % (fileName, repr(e).replace(',)', ')')))
try:
os.chmod(fileName, stat.S_IRUSR | stat.S_IWUSR)
except Exception as e:
return S_ERROR(DErrno.ESPF, "%s: %s" % (fileName, repr(e).replace(',)', ')')))
return S_OK(fileName)@convertToReturnValue
def writeToTokenFile(tokenContents, fileName=False):
""" Write a token string to file
:param str tokenContents: token as string
:param str fileName: filename to dump to
:return: S_OK(str)/S_ERROR()
"""
if not fileName:
fd, tokenLocation = tempfile.mkstemp()
os.close(fd)
fileName = tokenLocation
with open(fileName, 'wb') as fd:
fd.write(tokenContents)
os.chmod(fileName, stat.S_IRUSR | stat.S_IWUSR)
return fileNameIn fact, it's now obvious that |
|
I think what we should avoid is using our own exceptions in the DIRAC code. Otherwise there will be a mixture of two paradigms which is certainly worse than one or another. But of course we have to deal with exceptions in standard and third party modules. If this PR is to deal with these cases only and only when exceptions or failures in the called functions are not treated in the code of the caller, then these tools are quite appropriate. |
|
Any more ideas on this PR? The comments have been drying up lately. |
|
OK then I propose we just change the name of the method, and we merge it as is. The tool is good as it is, and then we can argue about its use on specific PRs |
f244b94 to
5d86385
Compare
2d5aa17 to
57c90a5
Compare
57c90a5 to
9a27529
Compare
This is an idea that I've been using for my own code with works which DIRAC which I think would be generally useful. As my explanation became a little long I've put it in a codimd document: https://codimd.web.cern.ch/8eEaG3lnRG2SiXCUS6WhFA#
If people approve of the idea I'll add tests and documentation.
BEGINRELEASENOTES
*Core
NEW: Add unwrap and convertReturnValue to simplify writing code with exceptions
ENDRELEASENOTES