(#19562) Asserts in Python stdlib code (datetime.py)

http://bugs.python.org/issue19562 propose to change the first assert in Lib/datetime.py assert 1 <= month <= 12, month to assert 1 <= month <= 12,'month must be in 1..12' to match the next two asserts out of the *53* in the file. I think that is the wrong direction of change, but that is not my question here. Should stdlib code use assert at all? If user input can trigger an assert, then the code should raise a normal exception that will not disappear with -OO. If the assert is testing program logic, then it seems that the test belongs in the test file, in this case, test/test_datetime.py. For example, consider the following (backwards) code. _DI4Y = _days_before_year(5) # A 4-year cycle has an extra leap day over what we'd get from pasting # together 4 single years. assert _DI4Y == 4 * 365 + 1 To me, the constant should be directly set to its known value. _DI4Y = 4*365 + 1. The function should then be tested in test_datetime. self.assertEqual(dt._days_before_year(5), dt._DI4Y) Is there any policy on use of assert in stdlib production code? -- Terry Jan Reedy

[Terry Reedy]
Should stdlib code use assert at all?
Of course, and for exactly the same reasons we use `assert()` in Python's C code: to verify preconditions, postconditions, and invariants that should never fail. Assertions should never be used to, e.g., verify user-supplied input (or anything else we believe _may_ fail).
If user input can trigger an assert, then the code should raise a normal exception that will not disappear with -OO.
Agreed.
I think making that change would be pointless code churn. Harmful, even. As the guy who happened to have written that code ;-), I think it's valuable to have the _code_ (not off buried in some monstrously tedious test file) explain what the comments there do explain, and verify with the assert. If anyone needs to muck with the implementation of datetime, it's crucial they understand what DI4Y _means_, and that it's identical to _days_before_year(5). Its actual value (4*365 + 1) isn't really interesting. Defining _DI4Y _as_ _days_before_year(5) captures its _meaning_. Ain't broke - don't fix.

On Fri, Nov 15, 2013 at 9:10 PM, Tim Peters <tim.peters@gmail.com> wrote:
Interestingly, the corresponding C code is closer to what Terry suggested: /* Number of days in 4, 100, and 400 year cycles. That these have * the correct values is asserted in the module init function. */ #define DI4Y 1461 /* days_before_year(5); days in 4 years */ #define DI100Y 36524 /* days_before_year(101); days in 100 years */ #define DI400Y 146097 /* days_before_year(401); days in 400 years */ ... skipping to the init function ... /* A 4-year cycle has an extra leap day over what we'd get from * pasting together 4 single years. */ assert(DI4Y == 4 * 365 + 1); assert(DI4Y == days_before_year(4+1)); This is probably explainable by the limitations of the C language, but I would find _DI4Y = 4 * 365 + 1 assert _DI4Y == _days_before_year(5) to be more natural than the way it is currently written.
Ain't broke - don't fix.
Agree.

On 16 November 2013 23:17, Maciej Fijalkowski <fijall@gmail.com> wrote:
"I don't care about embedded devices" is not a good rationale for killing features that really only benefit people running Python on such systems. Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia

On Sat, Nov 16, 2013 at 5:33 PM, Maciej Fijalkowski <fijall@gmail.com> wrote:
Or more importantly, how removing assert does. And how not naming it --remove-asserts would not help (people really have an opinion it would optimize their code)

On Sat, 16 Nov 2013 17:34:15 +0200 Maciej Fijalkowski <fijall@gmail.com> wrote:
I agree that conflating the two doesn't help the discussion. While removing docstrings may be beneficial on memory-constrained devices, I can't remember a single situation where I've wanted to remove asserts on a production system. (I also tend to write less and less asserts in production code, since all of them tend to go in unit tests instead, with the help of e.g. mock objects) Regards Antoine.

On 17 November 2013 01:46, Antoine Pitrou <solipsis@pitrou.net> wrote:
While I actually agree that having separate flags for --omit-debug, --omit-asserts and --omit-docstrings would make more sense than the current optimization levels, Maciej first proposed killing off -OO (where the most significant effect is removing docstrings which can result in substantial program footprint reductions for embedded systems), and only later switched to asking about removing asserts (part of -O, which also removes blocks guarded by "if __debug__", both of which help embedded systems preserve precious ROM space, although to a lesser degree than removing docstrings can save RAM). One of the most important questions to ask when proposing the removal of something is "What replacement are we offering for those users that actually need (or even just think they need) this feature?". Sometimes the answer is "Nothing", sometimes it's something that only covers a subset of previous use cases, and sometimes it's a complete functional equivalent with an improved spelling. But not asking the question at all (or, worse, dismissing the concerns of affected users as irrelevant and uninteresting) is a guaranteed way to annoy the very people that actually rely on the feature that is up for removal or replacement, when you *really* want them engaged and clearly explaining their use cases. Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia

Personally I think that none of the -O* should be removing asserts. It feels like a foot gun to me. I’ve seen more than one codebase that would be completely broken under -O* because they used asserts without even knowing -O* existed. Removing __debug__ blogs and doc strings I don’t think is as big of a deal, although removing doc strings can break code as well. On Nov 16, 2013, at 11:08 AM, Nick Coghlan <ncoghlan@gmail.com> wrote:
----------------- Donald Stufft PGP: 0x6E3CBCE93372DCFA // 7C6B 7C5D 5E2B 6356 A926 F04F 6E3C BCE9 3372 DCFA

On Sat, 16 Nov 2013 11:16:48 -0500 Donald Stufft <donald@stufft.io> wrote:
Originally it was probably done so as to mimick C, where compiling in optimized mode will indeed disable any assert()s in the code. Regards Antoine.

Hi, Some languages (C#, java) do the reverse by removing assertions if we don't tell compiler to keep them. Personnaly, I find this solution relatively accurate as I expect assertions not to be run in production. It would be painful to have this behaviour in python now, but I hope we'll keep a way to remove assertions and find interesting the solution of specific flags (--omit-debug, --omit-asserts and --omit-docstrings). cheers, Grégory 2013/11/16 Donald Stufft <donald@stufft.io>

On Sat, Nov 16, 2013 at 11:16:48AM -0500, Donald Stufft wrote:
I agree that many people misuse asserts. I agree that this is a problem for them. But I disagree that the solution is to remove what I consider to be a useful feature, and a common one in other languages, just to protect people from their broken code. I prefer to see better efforts to educate them. To that end, I've taken the liberty of sending a post to python-list@python.org describing when to use asserts, and when not to use them: https://mail.python.org/pipermail/python-list/2013-November/660401.html I will continue to use my best effort to encourage good use of assertions in Python. -- Steven

On Sat, Nov 16, 2013 at 04:46:00PM +0100, Antoine Pitrou wrote:
I'm the opposite. I like using asserts in my code, and while I don't *typically* run it with -O, I do think it is valuable to have to opportunity to remove asserts. I've certainly written code where -O has given a major micro-optimization of individual functions (anything up to 50% speedup). I've never measured if that lead to a significant whole-application speedup, but I assume that was some benefit. (I know, premature optimization and all that...) -- Steven

On Sun, Nov 17, 2013 at 11:00:50AM +0100, Antoine Pitrou wrote:
I had a demonstrable non-trivial speedup when timing individual functions. At the time I considered that "good enough". If you want to call that "premature optimization", I can't entirely disagree, but can you honestly say you've never done the same? Optimize a function to make it run faster, even if you have no proof that it was a bottleneck in the your application? -- Steven

On Sun, 17 Nov 2013 21:27:24 +1100 Steven D'Aprano <steve@pearwood.info> wrote:
You didn't answer my question: did you actually use -OO in production, or not? Saying that -OO could have helped you optimize something you didn't care about isn't a very strong argument for -OO :) What I would like to know is if people *knowingly* add costly asserts to performance-critical code, with the intent of disabling them at runtime using -OO. (in Python, that is, I know people do that in C where the programming culture and tools are different) Regards Antoine.

On Sun, Nov 17, 2013 at 11:35:21AM +0100, Antoine Pitrou wrote:
Ah, sorry, I misunderstood your question. I didn't use -OO, since I had no reason to remove docstrings. But I did use -O to remove asserts. I was talking about assertions, not docstrings. Since I haven't had to write code for embedded devices with severely constrained memory, I've never cared about using -OO in production.
Yes, I have knowingly added costly asserts to code with the intend of disabling them at runtime. Was it *performance-critical* code? I don't know, that was the point of my earlier rambling -- I could demonstrate a speedup of the individual functions in benchmarks, but nobody spent the effort to determine which functions were performance critical. -- Steven

Le 17/11/2013 12:27, Steven D'Aprano a écrit :
Hi, my 2 cents: asserts have been of a great help in the robustness of our provisioning framework, these are like tests embedded in code, to *consistently* check what would be VERY hard to test from the outside, from unit-tests. It makes us gain much time when we develop, because asserts (often used for "method contract checking") immediately break stuffs if we make dumb programming errors, like giving the wrong type of variable as parameter etc. (if you send a string instead of a list of strings to a method, it could take a while before the errors gets noticed, since their behaviour is quite close) We also add asserts with very expensive operations (like fully checking the proper synchronization of our DBs with the mockups of remote partners, after each provisioning command treated), so that we don't need to call something like that after every line of unit-test we write. In production, we then make sure we use -O flag to avoid doubling our treatments times and traffic. regards, Pascal

I believe the point of removing assertions is also to avoid throwing unhandled developper errors to end-user and not only "performance". It's like "raise" without "try" block. It's certainly because I consider "assert" as a developper util, providing a concrete documentation about methods signatures. In this idea I've made a small bench to determine if it is interesting for an assertion lib to have null functions as default. https://github.com/apieum/BenchAssert I don't make critical performance applications but still doubt of the real interest of having dead code to better document. 2013/11/17 Steven D'Aprano <steve@pearwood.info>

Gregory Salvan wrote:
I believe the point of removing assertions is also to avoid throwing unhandled developper errors to end-user
I'm not sure I buy that. An assert is saying that something should never happen. If it does happen, either it's going to lead to an exception further down the track, or produce incorrect results. In the first case, you've failed to shield the user from exceptions; in the second, better to log an exception than silently pretend nothing has gone wrong. -- Greg

On 17 November 2013 01:34, Maciej Fijalkowski <fijall@gmail.com> wrote:
No, that's the wrong question to ask. The onus is on *you* to ask "Who is this feature for? Do they still need it? Can we meet their needs in a different way?". You're the one proposing to break things, so it's up to you to make the case for why that's an OK thing to do. And until you ask those questions, and openly and honestly do the research to answer them (rather than assuming the answer you want), and can provide evidence of having done so, then it's entirely reasonable for me to dismiss the suggestion as you saying "this doesn't benefit me, so it doesn't benefit anyone, so it's OK to get rid of it". That's not the way this works - backwards compatibility is sacrosanct, and it requires some seriously compelling evidence to justify a breach. (This even applies to the Python 3 transition: the really annoying discrepancies between Python 2 and 3 are the ones where we allowed a backwards compatibility break without adequate justification, but now we're locked in to the decision due to internal backwards compatibility constraints within the Python 3 series). Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia

On Sun, Nov 17, 2013 at 01:50:31AM +1000, Nick Coghlan wrote:
Thanks for saying this. I get frustrated by the number of times people propose removing -O (apparently) just because they personally don't use it. I personally have never got any benefit from the tarfile or multiprocessing modules, but I don't ask for them to be removed :-) -- Steven

2013/11/16 Maciej Fijalkowski <fijall@gmail.com>:
Can I see some writeup how -OO benefit embedded devices?
You get smaller .pyc files. In an embedded device, the whole OS may be written in a small memory, something like 64 MB or smaller. Removing doctrings help to fit in 64 MB. I don't know if dropping "assert" statements is required on embedded device. Victor

On Sun, 17 Nov 2013 17:14:38 +0100, Victor Stinner <victor.stinner@gmail.com> wrote:
I've worked on a project (mobile platform) where both of these were true. Did we gain much by dropping asserts? As with Steve's case, no one bothered to measure, but it was a no-brainer win so we did it. Especially since we really needed to kill the docstrings to save memory. (Killing linecache was an even bigger win on the memory side). I unfortunately don't remember how much difference removing docstrings made in the process size, but I'm pretty sure it was more than a MB, and on a device with no swap in a process that must be running all the time, even 1MB makes a significant difference. On the assert side, if there hadn't been an option to remove the asserts, I'm sure that the call would have come down to manually remove all the asserts for production, which would have been a pain. In that case they *might* have measured, but since you'd have to do the removal work to do the measurement, they'd probably not have bothered. I'd say that if someone wants to drop assert removal, they'd need to prove that it *didn't* result in a speedup, which would be pretty hard considering that the checks covered by assert/if __debug__ can be arbitrarily complex :) But...yes, it would have been nice to have been able to remove docstrings and asserts *separately*. We might have measured the delta and decided to keep them in the beta in that case, since the asserts did catch some bugs. --David

On Nov 17, 2013, at 05:14 PM, Victor Stinner wrote:
I'm in support of separate flags for stripping docstrings and asserts. I'd even be fine with eliminating a flag to strip docstrings if we had a post-processing tool that you could apply to pyc files to strip out the docstrings. Another problem that I had while addressing these options in Debian was the use of .pyo for both -O and -OO level. -Barry

On Sun, Nov 17, 2013 at 9:02 PM, Barry Warsaw <barry@python.org> wrote:
My problem with -O and -OO is that their arguments are very circular. Indeed, I understand the need why you would want in certain and limited cases to remove both docstrings and asserts. So some options for doing so are ok. But a lot of arguments I see are along the lines of "don't use asserts because -O removes them". If the option was named --remove-asserts, noone would care, but people care since -O is documented as "do optimizations" and people *assume* this is what it does (makes code faster) and as unintended consequence removes asserts. Cheers, fijal

On Sun, Nov 17, 2013 at 1:05 PM, Maciej Fijalkowski <fijall@gmail.com>wrote:
It's circular indeed (and not just the shape of the letter :-). I expect that if there was a separate --remove-asserts option, people would write essential asserts and just claim "don't turn off asserts when using this code". But that's just wrong because such an option (whether named -O or --remove-asserts) is a global choice not under control of the author of the program. The correct rule should be "don't use assert (the statement) to check for valid user input" and the stated reason should be that the assert statement was *designed* to be disabled globally, not to be a shorthand for "if not X: raise (mumble) Y". A corollary should also be that unittests should not use the assert statement; some frameworks sadly encourage the anti-pattern of using it in tests. (There are valid reasons to want to run unittests with -O or -OO: for example, to validate that the code does not depend on side effects of assert statements. If there was a --remove-asserts option, running unittests with that option would be similarly useful.) That said I think our man page and --help output could be more forthcoming about this implication of "optimize". (The language reference is quite clear about it.) -- --Guido van Rossum (python.org/~guido)

17.11.2013 23:05, Guido van Rossum wrote:
My problem with -O (and -OO) is that even though my code is valid (in terms of the rule 'use assert only for should-never-happen cases') I have no control over 3rd party library code: I can never know whether doesn't it break if I turn -O or -OO on (as long as I do not analyze carefully the code of the libraries I use, including writing regression tests [for 3rd party code]...). Woudln't it to be useful to add possibility to place an "optimisation cookie" (syntactically analogous to "encoding cookie") at the beginning of each of my source files (when I know they are "-O"-safe), e.g.: # -*- opt: asserts -*- or even combined with an encoding cookie: # -*- coding: utf-8; opt: asserts, docstrings -*- Then: * The -O flag would be effectively applied *only* to a file containing such a cookie and *exactly* according to the cookie content (whether asserts, whether docstrings...). * Running without -O/-OO would mean ignoring optimisation cookies. * The -OO flag would mean removing both asserts and docstrings (i.e. the status quo of -OO). * Fine-grained explicit command line flags such as --remove-asserts and --remove-docstings could also be useful. (Of course, the '-*-' fragments in the above examples are purely conventional; the actual regex would not include them as it does not include them now for encoding cookies.) Cheers. *j

On Nov 17, 2013, at 11:05 PM, Maciej Fijalkowski wrote:
The reason I want to split them is more because I'd like an option to remove docstrings but not asserts. As others have also said, I use asserts for conditions that can't possibly happen (or so I think). E.g. using an if/elif on an enumeration where the else should never be hit. Or saying that after some calculation, this variable can never be None. In a sense, assertions are executable documentation about the state of behavior at a particular line of code. If an assert ever *does* get triggered, it means you didn't understand what you wrote. -Barry

[Terry Reedy]
Should stdlib code use assert at all?
Of course, and for exactly the same reasons we use `assert()` in Python's C code: to verify preconditions, postconditions, and invariants that should never fail. Assertions should never be used to, e.g., verify user-supplied input (or anything else we believe _may_ fail).
If user input can trigger an assert, then the code should raise a normal exception that will not disappear with -OO.
Agreed.
I think making that change would be pointless code churn. Harmful, even. As the guy who happened to have written that code ;-), I think it's valuable to have the _code_ (not off buried in some monstrously tedious test file) explain what the comments there do explain, and verify with the assert. If anyone needs to muck with the implementation of datetime, it's crucial they understand what DI4Y _means_, and that it's identical to _days_before_year(5). Its actual value (4*365 + 1) isn't really interesting. Defining _DI4Y _as_ _days_before_year(5) captures its _meaning_. Ain't broke - don't fix.

On Fri, Nov 15, 2013 at 9:10 PM, Tim Peters <tim.peters@gmail.com> wrote:
Interestingly, the corresponding C code is closer to what Terry suggested: /* Number of days in 4, 100, and 400 year cycles. That these have * the correct values is asserted in the module init function. */ #define DI4Y 1461 /* days_before_year(5); days in 4 years */ #define DI100Y 36524 /* days_before_year(101); days in 100 years */ #define DI400Y 146097 /* days_before_year(401); days in 400 years */ ... skipping to the init function ... /* A 4-year cycle has an extra leap day over what we'd get from * pasting together 4 single years. */ assert(DI4Y == 4 * 365 + 1); assert(DI4Y == days_before_year(4+1)); This is probably explainable by the limitations of the C language, but I would find _DI4Y = 4 * 365 + 1 assert _DI4Y == _days_before_year(5) to be more natural than the way it is currently written.
Ain't broke - don't fix.
Agree.

On 16 November 2013 23:17, Maciej Fijalkowski <fijall@gmail.com> wrote:
"I don't care about embedded devices" is not a good rationale for killing features that really only benefit people running Python on such systems. Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia

On Sat, Nov 16, 2013 at 5:33 PM, Maciej Fijalkowski <fijall@gmail.com> wrote:
Or more importantly, how removing assert does. And how not naming it --remove-asserts would not help (people really have an opinion it would optimize their code)

On Sat, 16 Nov 2013 17:34:15 +0200 Maciej Fijalkowski <fijall@gmail.com> wrote:
I agree that conflating the two doesn't help the discussion. While removing docstrings may be beneficial on memory-constrained devices, I can't remember a single situation where I've wanted to remove asserts on a production system. (I also tend to write less and less asserts in production code, since all of them tend to go in unit tests instead, with the help of e.g. mock objects) Regards Antoine.

On 17 November 2013 01:46, Antoine Pitrou <solipsis@pitrou.net> wrote:
While I actually agree that having separate flags for --omit-debug, --omit-asserts and --omit-docstrings would make more sense than the current optimization levels, Maciej first proposed killing off -OO (where the most significant effect is removing docstrings which can result in substantial program footprint reductions for embedded systems), and only later switched to asking about removing asserts (part of -O, which also removes blocks guarded by "if __debug__", both of which help embedded systems preserve precious ROM space, although to a lesser degree than removing docstrings can save RAM). One of the most important questions to ask when proposing the removal of something is "What replacement are we offering for those users that actually need (or even just think they need) this feature?". Sometimes the answer is "Nothing", sometimes it's something that only covers a subset of previous use cases, and sometimes it's a complete functional equivalent with an improved spelling. But not asking the question at all (or, worse, dismissing the concerns of affected users as irrelevant and uninteresting) is a guaranteed way to annoy the very people that actually rely on the feature that is up for removal or replacement, when you *really* want them engaged and clearly explaining their use cases. Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia

Personally I think that none of the -O* should be removing asserts. It feels like a foot gun to me. I’ve seen more than one codebase that would be completely broken under -O* because they used asserts without even knowing -O* existed. Removing __debug__ blogs and doc strings I don’t think is as big of a deal, although removing doc strings can break code as well. On Nov 16, 2013, at 11:08 AM, Nick Coghlan <ncoghlan@gmail.com> wrote:
----------------- Donald Stufft PGP: 0x6E3CBCE93372DCFA // 7C6B 7C5D 5E2B 6356 A926 F04F 6E3C BCE9 3372 DCFA

On Sat, 16 Nov 2013 11:16:48 -0500 Donald Stufft <donald@stufft.io> wrote:
Originally it was probably done so as to mimick C, where compiling in optimized mode will indeed disable any assert()s in the code. Regards Antoine.

Hi, Some languages (C#, java) do the reverse by removing assertions if we don't tell compiler to keep them. Personnaly, I find this solution relatively accurate as I expect assertions not to be run in production. It would be painful to have this behaviour in python now, but I hope we'll keep a way to remove assertions and find interesting the solution of specific flags (--omit-debug, --omit-asserts and --omit-docstrings). cheers, Grégory 2013/11/16 Donald Stufft <donald@stufft.io>

On Sat, Nov 16, 2013 at 11:16:48AM -0500, Donald Stufft wrote:
I agree that many people misuse asserts. I agree that this is a problem for them. But I disagree that the solution is to remove what I consider to be a useful feature, and a common one in other languages, just to protect people from their broken code. I prefer to see better efforts to educate them. To that end, I've taken the liberty of sending a post to python-list@python.org describing when to use asserts, and when not to use them: https://mail.python.org/pipermail/python-list/2013-November/660401.html I will continue to use my best effort to encourage good use of assertions in Python. -- Steven

On Sat, Nov 16, 2013 at 04:46:00PM +0100, Antoine Pitrou wrote:
I'm the opposite. I like using asserts in my code, and while I don't *typically* run it with -O, I do think it is valuable to have to opportunity to remove asserts. I've certainly written code where -O has given a major micro-optimization of individual functions (anything up to 50% speedup). I've never measured if that lead to a significant whole-application speedup, but I assume that was some benefit. (I know, premature optimization and all that...) -- Steven

On Sun, Nov 17, 2013 at 11:00:50AM +0100, Antoine Pitrou wrote:
I had a demonstrable non-trivial speedup when timing individual functions. At the time I considered that "good enough". If you want to call that "premature optimization", I can't entirely disagree, but can you honestly say you've never done the same? Optimize a function to make it run faster, even if you have no proof that it was a bottleneck in the your application? -- Steven

On Sun, 17 Nov 2013 21:27:24 +1100 Steven D'Aprano <steve@pearwood.info> wrote:
You didn't answer my question: did you actually use -OO in production, or not? Saying that -OO could have helped you optimize something you didn't care about isn't a very strong argument for -OO :) What I would like to know is if people *knowingly* add costly asserts to performance-critical code, with the intent of disabling them at runtime using -OO. (in Python, that is, I know people do that in C where the programming culture and tools are different) Regards Antoine.

On Sun, Nov 17, 2013 at 11:35:21AM +0100, Antoine Pitrou wrote:
Ah, sorry, I misunderstood your question. I didn't use -OO, since I had no reason to remove docstrings. But I did use -O to remove asserts. I was talking about assertions, not docstrings. Since I haven't had to write code for embedded devices with severely constrained memory, I've never cared about using -OO in production.
Yes, I have knowingly added costly asserts to code with the intend of disabling them at runtime. Was it *performance-critical* code? I don't know, that was the point of my earlier rambling -- I could demonstrate a speedup of the individual functions in benchmarks, but nobody spent the effort to determine which functions were performance critical. -- Steven

Le 17/11/2013 12:27, Steven D'Aprano a écrit :
Hi, my 2 cents: asserts have been of a great help in the robustness of our provisioning framework, these are like tests embedded in code, to *consistently* check what would be VERY hard to test from the outside, from unit-tests. It makes us gain much time when we develop, because asserts (often used for "method contract checking") immediately break stuffs if we make dumb programming errors, like giving the wrong type of variable as parameter etc. (if you send a string instead of a list of strings to a method, it could take a while before the errors gets noticed, since their behaviour is quite close) We also add asserts with very expensive operations (like fully checking the proper synchronization of our DBs with the mockups of remote partners, after each provisioning command treated), so that we don't need to call something like that after every line of unit-test we write. In production, we then make sure we use -O flag to avoid doubling our treatments times and traffic. regards, Pascal

I believe the point of removing assertions is also to avoid throwing unhandled developper errors to end-user and not only "performance". It's like "raise" without "try" block. It's certainly because I consider "assert" as a developper util, providing a concrete documentation about methods signatures. In this idea I've made a small bench to determine if it is interesting for an assertion lib to have null functions as default. https://github.com/apieum/BenchAssert I don't make critical performance applications but still doubt of the real interest of having dead code to better document. 2013/11/17 Steven D'Aprano <steve@pearwood.info>

Gregory Salvan wrote:
I believe the point of removing assertions is also to avoid throwing unhandled developper errors to end-user
I'm not sure I buy that. An assert is saying that something should never happen. If it does happen, either it's going to lead to an exception further down the track, or produce incorrect results. In the first case, you've failed to shield the user from exceptions; in the second, better to log an exception than silently pretend nothing has gone wrong. -- Greg

On 17 November 2013 01:34, Maciej Fijalkowski <fijall@gmail.com> wrote:
No, that's the wrong question to ask. The onus is on *you* to ask "Who is this feature for? Do they still need it? Can we meet their needs in a different way?". You're the one proposing to break things, so it's up to you to make the case for why that's an OK thing to do. And until you ask those questions, and openly and honestly do the research to answer them (rather than assuming the answer you want), and can provide evidence of having done so, then it's entirely reasonable for me to dismiss the suggestion as you saying "this doesn't benefit me, so it doesn't benefit anyone, so it's OK to get rid of it". That's not the way this works - backwards compatibility is sacrosanct, and it requires some seriously compelling evidence to justify a breach. (This even applies to the Python 3 transition: the really annoying discrepancies between Python 2 and 3 are the ones where we allowed a backwards compatibility break without adequate justification, but now we're locked in to the decision due to internal backwards compatibility constraints within the Python 3 series). Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia

On Sun, Nov 17, 2013 at 01:50:31AM +1000, Nick Coghlan wrote:
Thanks for saying this. I get frustrated by the number of times people propose removing -O (apparently) just because they personally don't use it. I personally have never got any benefit from the tarfile or multiprocessing modules, but I don't ask for them to be removed :-) -- Steven

2013/11/16 Maciej Fijalkowski <fijall@gmail.com>:
Can I see some writeup how -OO benefit embedded devices?
You get smaller .pyc files. In an embedded device, the whole OS may be written in a small memory, something like 64 MB or smaller. Removing doctrings help to fit in 64 MB. I don't know if dropping "assert" statements is required on embedded device. Victor

On Sun, 17 Nov 2013 17:14:38 +0100, Victor Stinner <victor.stinner@gmail.com> wrote:
I've worked on a project (mobile platform) where both of these were true. Did we gain much by dropping asserts? As with Steve's case, no one bothered to measure, but it was a no-brainer win so we did it. Especially since we really needed to kill the docstrings to save memory. (Killing linecache was an even bigger win on the memory side). I unfortunately don't remember how much difference removing docstrings made in the process size, but I'm pretty sure it was more than a MB, and on a device with no swap in a process that must be running all the time, even 1MB makes a significant difference. On the assert side, if there hadn't been an option to remove the asserts, I'm sure that the call would have come down to manually remove all the asserts for production, which would have been a pain. In that case they *might* have measured, but since you'd have to do the removal work to do the measurement, they'd probably not have bothered. I'd say that if someone wants to drop assert removal, they'd need to prove that it *didn't* result in a speedup, which would be pretty hard considering that the checks covered by assert/if __debug__ can be arbitrarily complex :) But...yes, it would have been nice to have been able to remove docstrings and asserts *separately*. We might have measured the delta and decided to keep them in the beta in that case, since the asserts did catch some bugs. --David

On Nov 17, 2013, at 05:14 PM, Victor Stinner wrote:
I'm in support of separate flags for stripping docstrings and asserts. I'd even be fine with eliminating a flag to strip docstrings if we had a post-processing tool that you could apply to pyc files to strip out the docstrings. Another problem that I had while addressing these options in Debian was the use of .pyo for both -O and -OO level. -Barry

On Sun, Nov 17, 2013 at 9:02 PM, Barry Warsaw <barry@python.org> wrote:
My problem with -O and -OO is that their arguments are very circular. Indeed, I understand the need why you would want in certain and limited cases to remove both docstrings and asserts. So some options for doing so are ok. But a lot of arguments I see are along the lines of "don't use asserts because -O removes them". If the option was named --remove-asserts, noone would care, but people care since -O is documented as "do optimizations" and people *assume* this is what it does (makes code faster) and as unintended consequence removes asserts. Cheers, fijal

On Sun, Nov 17, 2013 at 1:05 PM, Maciej Fijalkowski <fijall@gmail.com>wrote:
It's circular indeed (and not just the shape of the letter :-). I expect that if there was a separate --remove-asserts option, people would write essential asserts and just claim "don't turn off asserts when using this code". But that's just wrong because such an option (whether named -O or --remove-asserts) is a global choice not under control of the author of the program. The correct rule should be "don't use assert (the statement) to check for valid user input" and the stated reason should be that the assert statement was *designed* to be disabled globally, not to be a shorthand for "if not X: raise (mumble) Y". A corollary should also be that unittests should not use the assert statement; some frameworks sadly encourage the anti-pattern of using it in tests. (There are valid reasons to want to run unittests with -O or -OO: for example, to validate that the code does not depend on side effects of assert statements. If there was a --remove-asserts option, running unittests with that option would be similarly useful.) That said I think our man page and --help output could be more forthcoming about this implication of "optimize". (The language reference is quite clear about it.) -- --Guido van Rossum (python.org/~guido)

17.11.2013 23:05, Guido van Rossum wrote:
My problem with -O (and -OO) is that even though my code is valid (in terms of the rule 'use assert only for should-never-happen cases') I have no control over 3rd party library code: I can never know whether doesn't it break if I turn -O or -OO on (as long as I do not analyze carefully the code of the libraries I use, including writing regression tests [for 3rd party code]...). Woudln't it to be useful to add possibility to place an "optimisation cookie" (syntactically analogous to "encoding cookie") at the beginning of each of my source files (when I know they are "-O"-safe), e.g.: # -*- opt: asserts -*- or even combined with an encoding cookie: # -*- coding: utf-8; opt: asserts, docstrings -*- Then: * The -O flag would be effectively applied *only* to a file containing such a cookie and *exactly* according to the cookie content (whether asserts, whether docstrings...). * Running without -O/-OO would mean ignoring optimisation cookies. * The -OO flag would mean removing both asserts and docstrings (i.e. the status quo of -OO). * Fine-grained explicit command line flags such as --remove-asserts and --remove-docstings could also be useful. (Of course, the '-*-' fragments in the above examples are purely conventional; the actual regex would not include them as it does not include them now for encoding cookies.) Cheers. *j

On Nov 17, 2013, at 11:05 PM, Maciej Fijalkowski wrote:
The reason I want to split them is more because I'd like an option to remove docstrings but not asserts. As others have also said, I use asserts for conditions that can't possibly happen (or so I think). E.g. using an if/elif on an enumeration where the else should never be hit. Or saying that after some calculation, this variable can never be None. In a sense, assertions are executable documentation about the state of behavior at a particular line of code. If an assert ever *does* get triggered, it means you didn't understand what you wrote. -Barry
participants (17)
-
Alexander Belopolsky
-
Antoine Pitrou
-
Barry Warsaw
-
Donald Stufft
-
Greg Ewing
-
Gregory Salvan
-
Guido van Rossum
-
Jan Kaliszewski
-
Maciej Fijalkowski
-
Mark Janssen
-
Nick Coghlan
-
Pascal Chambon
-
R. David Murray
-
Steven D'Aprano
-
Terry Reedy
-
Tim Peters
-
Victor Stinner