473,480 Members | 1,940 Online
Bytes | Software Development & Data Engineering Community
Create Post

Home Posts Topics Members FAQ

PEP new assert idiom

I'm sorry if it's an replicate. Either my e-mail program is messing with
things or the python-list sent my msg to /dev/null. I couldn't find
anything related in previous PEP's, so here it goes a very early draft
for a new "assert" syntax:

This was inspired in Ruby's assert syntax. I'm not familiar with Ruby at
all, so the chances are that this piece of code is broken, but I think
the idea is very obvious. In Ruby, assert is simply a method which gets
a block argument:
assert 'Errormsg' {
statement 1
statement 2
(...)
statement n
}
This elegant syntax is NOT equivalent to python's not so ellegant:
erromsg = 'Errormsg'
assert statement 1, errormsg
assert statement 2, 'errormsg
(...)
assert statement n, errormsg
In Ruby, the Assertion error is raised if executing statement 1, then 2,
then 3... etc raises an error. This is a subtle thingm the error COULD
NOT be raised if each statement is executed alone, as each statement may
have side effects which make the order of execution relevant. To
suceccefully emulate this behaviour, the python programmer have to
resort to a even more cumbersome solution:
foo = lambda : (statement 1) and (statement 2) ... (statement n)
assert foo, 'Errormsg'
My proposal is to add the following syntax to the language:
assert (statement 1), (statement 2), ... (statement n), 'Errormsg'
Or, if the user prefers, the traditional comma rules also applies:
assert \
statement1,
statement2,
(...)
statement n,
'Errormsg'
This simple syntax change introduces a very useful idiom for unittesting
and may equally be useful in other kinds of code. The most problematic
issue, I see, is the potential ambiguity a assert usage:
assert statement 1, ..., statement n, string
As the 'Errormsg' argument is optional, it could be interpreted either
as being the statement (n + 1) or as the errormsg. This is not a
non-issue as the following syntax is valid in the current implementation
and is very useful:
st = ''
assert st Traceback
....
AssertionError

This is useful to assert that a string is not empty. My proposal is that
assert will always check all statements, (including the eventual error
message) and issue AssertError exceptions if find any problem. This will
catch only empty strings. If the last argument is a string, and an a
False statement was found, it will print the last argument in the shell.

The only piece of code I see would be broken in the new implementation
is:
assert statement, ''


This will always raise an exception in the new implementation on the
opposition to the current behaviour in which the exception is raised
only if 'statement' is false, returning an empty error message. I don't
see any use for this pattern of code and is very unlikelly anyone has
ever implemented it, so I guess nobody would mind breaking this.

I'm interested to write a formal PEP if I receive good feedback from the
community, but I never wrote a PEP before, and (the worst problem) my
english is not so good. Anyone helps?

Thanks,
Fabio
Jul 18 '05 #1
28 3536
Fábio Mendes <ni********@uol.com.br> wrote:
...
This elegant syntax is NOT equivalent to python's not so ellegant:
erromsg = 'Errormsg'
assert statement 1, errormsg
assert statement 2, 'errormsg
(...)
assert statement n, errormsg

Why isn't this equivalent? Apart from the fact that you keep, here and
elsewhere, using 'statement' where you hopefully mean 'expression' --
you cannot assert a statement, you can only assert an expression.
In Ruby, the Assertion error is raised if executing statement 1, then 2,
then 3... etc raises an error. This is a subtle thingm the error COULD
NOT be raised if each statement is executed alone, as each statement may
have side effects which make the order of execution relevant. To
Can you give one Python example where the sequence of asserts would
behave differently from what you propose? I cannot see any.
suceccefully emulate this behaviour, the python programmer have to
resort to a even more cumbersome solution:
foo = lambda : (statement 1) and (statement 2) ... (statement n)
assert foo, 'Errormsg'

I assume you mean to call foo, because if you don't, it will surely be
true and the assert will just never trigger.

Now, calling expressions expressions, rather than very confusingly
statements, can you explain how the semantics of this, with foo being
called, would differ from those of

assert exp1 and exp2 and exp3 ... and expN, 'errormsg'

???

My proposal is to add the following syntax to the language:
assert (statement 1), (statement 2), ... (statement n), 'Errormsg'

Again: can you explain how the semantics of this, would differ from
those of:

assert exp1 and exp2 and exp3 ... and expN, 'errormsg'

???
Or, if the user prefers, the traditional comma rules also applies:


There is no such "traditional" rule (or rules) in Python. Both a
statement and an expression can perfectly well end in a comma; the comma
does NOT imply any kind of continuation.
Alex
Jul 18 '05 #2
"Fábio Mendes" <ni********@uol.com.br> wrote in message
news:ma**************************************@pyth on.org...
I'm sorry if it's an replicate. Either my e-mail program is messing with
things or the python-list sent my msg to /dev/null. I couldn't find
anything related in previous PEP's, so here it goes a very early draft
for a new "assert" syntax:


Do you have a use case? That is, can you give a plausible example that
shows why your proposal would be useful and how it would work?
Jul 18 '05 #3

"Fábio Mendes" <ni********@uol.com.br> wrote in message
news:ma**************************************@pyth on.org...
I'm sorry if it's an replicate. Either my e-mail program is messing with
things or the python-list sent my msg to /dev/null. I couldn't find
anything related in previous PEP's, so here it goes a very early draft
for a new "assert" syntax:
[...]
I'm interested to write a formal PEP if I receive good feedback from the
community, but I never wrote a PEP before, and (the worst problem) my
english is not so good. Anyone helps?

Thanks,
Fabio


I see two difficulties with it.

First, you can do the same thing (I think) with a
try block around a sequence of statements and
an assert in the except block. This means you
will need a fairly strong use case based on
convenience to add the syntax to the language.
You will have to show that it will be used a lot.

Second, the statement form has the potential to
cause side effects. There is a very strong
community of thought that says that asserts
are debugging or validation statements that
should not cause any behavior change by
removing them. This can be dealt with by
making it some form of block that has its
own local variables that are discarded on
exit.

John Roth

Jul 18 '05 #4
> > >>> erromsg = 'Errormsg'
>> assert statement 1, errormsg
>> assert statement 2, 'errormsg
>> (...)
>> assert statement n, errormsg

Why isn't this equivalent? Apart from the fact that you keep, here and
elsewhere, using 'statement' where you hopefully mean 'expression' --
you cannot assert a statement, you can only assert an expression.


There is only the conceptually subtle difference that in the 1st you
asserts the whole block of expressions, the second you assert each
expression. They're likely to be the same, probably they will be
equivalent in all cases but I can't backup the truth or falsity of that
statement. The pythonic counterpart involves too much typing and is more
error prone.
Now, calling expressions expressions, rather than very confusingly
statements, can you explain how the semantics of this, with foo being
called, would differ from those of

assert exp1 and exp2 and exp3 ... and expN, 'errormsg'


This is very similar to what I'm proposing, with the only inconvinience
that is uglier to type:

assert \
exp1 and \
exp2 and \
...
expn,
'ErrorMsg'

Instead of:

assert \
exp1,
exp2,
...
expn,
'Errormsg'

Well, I realize I didn't expressed my thoughts very clearly and that
it's indeed a very minor change in python's syntax. It won't let anyone
does anything new, IFAIK, but it makes a common pattern of code a little
more beautiful, (and why not? more expressive). If one consider the fact
that it won't break old code (only in one very unlikely case) I don't
see it as a completely unreasonable suggestion. Other people may think
differently though.

Thanks,
Fabio
Jul 18 '05 #5
> I see two difficulties with it.

First, you can do the same thing (I think) with a
try block around a sequence of statements and
an assert in the except block. This means you
will need a fairly strong use case based on
convenience to add the syntax to the language.
You will have to show that it will be used a lot.


I meant expression instead of statement, sorry, that's my fault. It's a
minor cosmetic change I should say, only to avoid long grouping of
expressions with an 'and' operator. It's better expressed as: let the
commas take the place of 'and' in assertion verifications... Maybe that
could be extended to other parts of the language, but the only place I
think it would be useful is in assertion statements.

Thanks,
Fabio
Jul 18 '05 #6
[Fábio Mendes]
This is very similar to what I'm proposing, with the only inconvinience
that is uglier to type:

assert \
exp1 and \
exp2 and \
...
expn,
'ErrorMsg'

Instead of:

assert \
exp1,
exp2,
...
expn,
'Errormsg'

Well, I realize I didn't expressed my thoughts very clearly and that
it's indeed a very minor change in python's syntax. It won't let anyone
does anything new, IFAIK, but it makes a common pattern of code a little
more beautiful, (and why not? more expressive). If one consider the fact
that it won't break old code (only in one very unlikely case) I don't
see it as a completely unreasonable suggestion. Other people may think
differently though.


The odds of Guido accepting this proposal are about zero. As you say, it
doesn't do anything new, but it does require altering the grammar. Besides,
TOOWTDI.

Also, Guido tends to not be persuaded by arguments about "too much typing".
This is doubly true is you're talking about replacing an "and" with a comma (big
whoop).

Also, one of the existing alternatives is quite readable:

err = 'Errormsg'
assert exp1, err
assert exp2, err
assert exp3, err

The alternative has the advantage that a failure will point to the exact
expression that failed. The disadvantage is the repetition of the error
message; however, I disagree that your use case is common. Instead, it is
likely more advantageous to have different error messages for each expression.
For example, the following comes from the post condition checks in QR matrix
decomposition:

assert Q.tr().mmul(Q)==eye(min(m,n)), "Q is not orthonormal"
assert isinstance(R,UpperTri), "R is not upper triangular"
assert R.size==(m,n), "R is does not match the original dimensions"
assert Q.mmul(R)==self, "Q*R does not reproduce the original matrix"

One could link all of these by an "and" or the proposed comma, but then you
end-up with a single, less informative error message, "The QR decomposition
bombed, but I won't tell you why ;-) ".
Raymond Hettinger
Jul 18 '05 #7
Some time ago I found myself proposing a new "Validate" statement,
which would work exactly like "assert", except:

1) it would throw a ValidationError instead of AssertionError
if the condition failed

2) it would NOT be turned into a no-op by the optimizing compiler.

The purpose is runtime validation of user data, rather than sanity
checking the program logic. Example: I keep finding myself writing
code like:

x = float(raw_input('Enter a positive number: '))
assert x > 0, 'number wasn't positive'

This is incorrect because the assert statement is not guaranteed to be
executed. I propose to say instead,

validate x > 0, 'number wasn't positive'

which would do the right thing.

This proposal was reasonably well received when I've posted it before,
but I don't remember if there was any conclusion, and there was no
follow-up. Since we're again talking about PEP's regarding the assert
statement, should I try to put one together for this, in my copious
(hah) free time?
Jul 18 '05 #8
> Some time ago I found myself proposing a new "Validate" statement,
which would work exactly like "assert", except:

1) it would throw a ValidationError instead of AssertionError
if the condition failed

2) it would NOT be turned into a no-op by the optimizing compiler.

[...]
This sounds great. I like the validate syntax. This also sounds very
useful to me. If it doesn't go mainstream, it should, at least be a
parameter controlled at runtime:
import validate
validate.always_compile_assertions = True # this name sucks! I know!
Ideally, for me, python would support a decent DPC-like semantics:
class foo_bar:
contract, 'invariant':
assert (something always true), 'Errormsg1'
assert (more imutable truths), 'Errormsg2'

def foo(self, var1, var2):
contract, 'pre':
# var1 and var2 are avaiable in this scope
assert expr, 'Error string1'
assert expr1, expr2, 'Error string2'

contract, 'pos':
# var1, var2, avaiable. 'old' is 'self' before calling foo
# foo.return stands for the output of function foo (or None)
# foo.error is any the exception the function had trown
assert self.bar > old.bar
assert foo == some result, 'Error string'
if foo.error == some Exception:
assert (condition to trow that exception), 'Error'

(function implementation)

The (python) implementation of this syntax can be something like this.
If dbc is enable, foo method becames:
def foo(self, var1, var2):
try:
contract invariant block
...
except AssertionError, x:
contractViolations.log('invariant', x)

try:
pre contract block
...
except AssertionError, x:
contractViolations.log('pre', x)
try:
foo.value = __old_foo(var1, var2)
finally error, error_msg:
if error: foo.value = None
foo.error = error
try:
post contract block
except AssertionError, x:
contractViolations.log('pos', x)
if error and not contract.fail_silently:
raise error, error_msg


The program executes normally, then, if non fatal errors happens,
contracViolations.report() will print a nice formated report of what was
violated, similar to what unittest module does. This is not pure DBC I
guess, but is nice.

Thanks,
Fabio
Jul 18 '05 #9
> The alternative has the advantage that a failure will point to the exact
expression that failed. The disadvantage is the repetition of the error
message; however, I disagree that your use case is common. Instead, it is
likely more advantageous to have different error messages for each expression.
For example, the following comes from the post condition checks in QR matrix
decomposition:

assert Q.tr().mmul(Q)==eye(min(m,n)), "Q is not orthonormal"
assert isinstance(R,UpperTri), "R is not upper triangular"
assert R.size==(m,n), "R is does not match the original dimensions"
assert Q.mmul(R)==self, "Q*R does not reproduce the original matrix"

One could link all of these by an "and" or the proposed comma, but then you
end-up with a single, less informative error message, "The QR decomposition
bombed, but I won't tell you why ;-) ".

You have a good point here. Maybe what I proposed is only a distraction.
We don't want a syntax tailored to every sittuation as it will serve
only for showcase selected programs that express the full elegance of
the language, but to the programmer, it gains the burden of memorizing
the 100 and so operators that makes the language very expressive. Of
course each person will develop a personal dialect, which will make his
code very expressive in a specific domain, but he'll talk to
nobodyelse... For that we have perl. So I guess i'm off this thread, but
someone pointed a PEP for a 'validate' statement which still holds. At
least it will help to elucidate the somewhat confusing meaning of the
assert statement. (you shouldn't use it at runtime?? which level of
optimizations disable it?).

Fabio
Jul 18 '05 #10

"Paul Rubin" <http://ph****@NOSPAM.invalid> wrote in message
news:7x************@ruckus.brouhaha.com...
Some time ago I found myself proposing a new "Validate" statement,
which would work exactly like "assert", except:

1) it would throw a ValidationError instead of AssertionError
if the condition failed

2) it would NOT be turned into a no-op by the optimizing compiler.

The purpose is runtime validation of user data, rather than sanity
checking the program logic. Example: I keep finding myself writing
code like:

x = float(raw_input('Enter a positive number: '))
assert x > 0, 'number wasn't positive'

This is incorrect because the assert statement is not guaranteed to be
executed. I propose to say instead,

validate x > 0, 'number wasn't positive'

which would do the right thing.


Why do you need a statement for this?
IMO, a plain function will do the trick:

def validate(expression, msg=None):
if expression: return
if msg is None:
raise ValidationError
else
raise ValidationError(msg)
Raymond Hettinger
Jul 18 '05 #11
"Raymond Hettinger" <vz******@verizon.net> writes:
Why do you need a statement for this?
IMO, a plain function will do the trick:


I do write such functions sometimes, but using a statement is more
natural. That's why the assert statement exists, for example.

Because of that naturalness, the temptation to misuse the assert
statement is very great, and I find myself doing it all the time
thinking I'll clean it up later. So I think having a statement for
runtime checking would be in the correct spirit.
Jul 18 '05 #12
Fábio Mendes <ni********@uol.com.br> wrote:
...
called, would differ from those of

assert exp1 and exp2 and exp3 ... and expN, 'errormsg'


This is very similar to what I'm proposing, with the only inconvinience
that is uglier to type:

assert \
exp1 and \
exp2 and \
...
expn,
'ErrorMsg'

Instead of:

assert \
exp1,
exp2,
...
expn,
'Errormsg'


So follow PEP 8's recommendation instead:

assert (
exp1 and
exp2 and
...
expn
), 'Errormsg'

I don't see the parentheses (which clarify the syntax issue you
mentioned in your first post) and 'and' as any uglier than the commas.
And having commas mean line continuation is out of the question.
Alex
Jul 18 '05 #13
On Sun, 07 Nov 2004 03:50:43 GMT, "Raymond Hettinger" <vz******@verizon.net> wrote:
[Fábio Mendes]
This is very similar to what I'm proposing, with the only inconvinience
that is uglier to type:

assert \
exp1 and \
exp2 and \
...
expn,
'ErrorMsg'

Instead of:

assert \
exp1,
exp2,
...
expn,
'Errormsg'

Well, I realize I didn't expressed my thoughts very clearly and that
it's indeed a very minor change in python's syntax. It won't let anyone
does anything new, IFAIK, but it makes a common pattern of code a little
more beautiful, (and why not? more expressive). If one consider the fact
that it won't break old code (only in one very unlikely case) I don't
see it as a completely unreasonable suggestion. Other people may think
differently though.


The odds of Guido accepting this proposal are about zero. As you say, it
doesn't do anything new, but it does require altering the grammar. Besides,
TOOWTDI.

Also, Guido tends to not be persuaded by arguments about "too much typing".
This is doubly true is you're talking about replacing an "and" with a comma (big
whoop).

Also, one of the existing alternatives is quite readable:

err = 'Errormsg'
assert exp1, err
assert exp2, err
assert exp3, err

The alternative has the advantage that a failure will point to the exact
expression that failed. The disadvantage is the repetition of the error
message; however, I disagree that your use case is common. Instead, it is
likely more advantageous to have different error messages for each expression.
For example, the following comes from the post condition checks in QR matrix
decomposition:

assert Q.tr().mmul(Q)==eye(min(m,n)), "Q is not orthonormal"
assert isinstance(R,UpperTri), "R is not upper triangular"
assert R.size==(m,n), "R is does not match the original dimensions"
assert Q.mmul(R)==self, "Q*R does not reproduce the original matrix"

One could link all of these by an "and" or the proposed comma, but then you
end-up with a single, less informative error message, "The QR decomposition
bombed, but I won't tell you why ;-) ".

Besides, if you want the single message with comma-delimited expressions,
you can already write:
assert False not in map(bool, ( ... True,
... 1,
... 2==2
... )), 'Error message'

Or to show what happens assert False not in map(bool, ( ... True,
... 1,
... 2==3
... )), 'Error message'
Traceback (most recent call last):
File "<stdin>", line 1, in ?
AssertionError: Error message

Or with a little helper, and then two boilerplate lines for the assert,
you can have individual messages:
def fff(*xm): ... """find first false xpr in seq xpr ,msg, xpr, msg and yield pair"""
... it = iter(xm)
... for x in it:
... m = it.next()
... if not x: yield x, m; break
... def test(x): ... assert not [t for t in fff(
...
... True, 'true msg',
... 1, 'one msg',
... 2==x, '2 eq x msg',
... 'xx', 'xx msg'
...
... )], 'Error: expr == %r, msg = %r'%t
... test(2)
test(3) Traceback (most recent call last):
File "<stdin>", line 1, in ?
File "<stdin>", line 7, in test
AssertionError: Error: expr == False, msg = '2 eq x msg'

Actually, why not just make a utility function "asserts" to do it:
def asserts(*expr_msg_seq): ... """find first false expression value and assert it with paired message"""
... it = iter(expr_msg_seq)
... for x in it:
... m = it.next()
... if not x:
... assert x, '%r -> %r'%(x, m)
... def test(x): ... asserts(
... True, 'true msg',
... 1, 'one msg',
... x, 'bool(x) is not True',
... x==2, '2 eq x msg',
... 'xx', 'xx msg'
... )
... test(2)
test(3) Traceback (most recent call last):
File "<stdin>", line 1, in ?
File "<stdin>", line 7, in test
File "<stdin>", line 7, in asserts
AssertionError: False -> '2 eq x msg' test(0) Traceback (most recent call last):
File "<stdin>", line 1, in ?
File "<stdin>", line 7, in test
File "<stdin>", line 7, in asserts
AssertionError: 0 -> 'bool(x) is not True' test(()) Traceback (most recent call last):
File "<stdin>", line 1, in ?
File "<stdin>", line 7, in test
File "<stdin>", line 7, in asserts
AssertionError: () -> 'bool(x) is not True' test(type('foo',(),{'__nonzero__':lambda self:0})()) Traceback (most recent call last):
File "<stdin>", line 1, in ?
File "<stdin>", line 7, in test
File "<stdin>", line 7, in asserts
AssertionError: <__main__.foo object at 0x02EF17AC> -> 'bool(x) is not True' test(type('foo',(),{'__nonzero__':lambda self:1})()) Traceback (most recent call last):
File "<stdin>", line 1, in ?
File "<stdin>", line 7, in test
File "<stdin>", line 7, in asserts
AssertionError: False -> '2 eq x msg' test(type('foo',(),{'__nonzero__':lambda self:1, '__cmp__':lambda s,o:0})())


I doesn't shortcut, so you could get an exception in preparing the arg list for
a sequence like
asserts(
den !=0, 'denom must be zero',
num/den>5, 'better write it as assert num>5*den'
)
which would be safer as
assert den !=0, 'denom must be zero'
assert num/den>5 'better write it as assert num>5*den'

Not to mention side effects, but you shouldn't have those in asserts anyway.

Silliness ;-)

Regards,
Bengt Richter
Jul 18 '05 #14
Em Sáb, 2004-11-06 Ã*s 22:48 -0800, Paul Rubin escreveu:
"Raymond Hettinger" <vz******@verizon.net> writes:
Why do you need a statement for this?
IMO, a plain function will do the trick:


I do write such functions sometimes, but using a statement is more
natural. That's why the assert statement exists, for example.

Because of that naturalness, the temptation to misuse the assert
statement is very great, and I find myself doing it all the time
thinking I'll clean it up later. So I think having a statement for
runtime checking would be in the correct spirit.


If it wasn't that we should be programming in assembly as it's faster :)
AFAIK all real world programming languages are turing equivalent, so
sugar is what differentiates on of the other. I'd love to see that sugar
in Python since defining assert functions is distracting.

Fabio
Jul 18 '05 #15
> So follow PEP 8's recommendation instead:

assert (
exp1 and
exp2 and
...
expn
), 'Errormsg'
I didn't know this would work for 'and/or' operators (even I've read the
style guide PEP!), sorry. It's not super beautiful, but I could live
happy with that :)
I don't see the parentheses (which clarify the syntax issue you
mentioned in your first post) and 'and' as any uglier than the commas.
And having commas mean line continuation is out of the question.


I never said that commas should mean line continuation (as a backslash).
It CAN be used as implicit line continuations in lot cases, (like
function arguments, for instance. This would be just one more case.

Cheers,
Fabio
Jul 18 '05 #16
Thanks for clarification :-)

Fabio

Em Dom, 2004-11-07 Ã*s 07:43 +0000, Bengt Richter escreveu:
On Sun, 07 Nov 2004 03:50:43 GMT, "Raymond Hettinger" <vz******@verizon.net> wrote:
[Fbio Mendes]
This is very similar to what I'm proposing, with the only inconvinience
that is uglier to type:

assert \
exp1 and \
exp2 and \
...
expn,
'ErrorMsg'

Instead of:

assert \
exp1,
exp2,
...
expn,
'Errormsg'

Well, I realize I didn't expressed my thoughts very clearly and that
it's indeed a very minor change in python's syntax. It won't let anyone
does anything new, IFAIK, but it makes a common pattern of code a little
more beautiful, (and why not? more expressive). If one consider the fact
that it won't break old code (only in one very unlikely case) I don't
see it as a completely unreasonable suggestion. Other people may think
differently though.


The odds of Guido accepting this proposal are about zero. As you say, it
doesn't do anything new, but it does require altering the grammar. Besides,
TOOWTDI.

Also, Guido tends to not be persuaded by arguments about "too much typing".
This is doubly true is you're talking about replacing an "and" with a comma (big
whoop).

Also, one of the existing alternatives is quite readable:

err = 'Errormsg'
assert exp1, err
assert exp2, err
assert exp3, err

The alternative has the advantage that a failure will point to the exact
expression that failed. The disadvantage is the repetition of the error
message; however, I disagree that your use case is common. Instead, it is
likely more advantageous to have different error messages for each expression.
For example, the following comes from the post condition checks in QR matrix
decomposition:

assert Q.tr().mmul(Q)==eye(min(m,n)), "Q is not orthonormal"
assert isinstance(R,UpperTri), "R is not upper triangular"
assert R.size==(m,n), "R is does not match the original dimensions"
assert Q.mmul(R)==self, "Q*R does not reproduce the original matrix"

One could link all of these by an "and" or the proposed comma, but then you
end-up with a single, less informative error message, "The QR decomposition
bombed, but I won't tell you why ;-) ".

Besides, if you want the single message with comma-delimited expressions,
you can already write:
>>> assert False not in map(bool, ( ... True,
... 1,
... 2==2
... )), 'Error message'

Or to show what happens >>> assert False not in map(bool, ( ... True,
... 1,
... 2==3
... )), 'Error message'
Traceback (most recent call last):
File "<stdin>", line 1, in ?
AssertionError: Error message

Or with a little helper, and then two boilerplate lines for the assert,
you can have individual messages:
>>> def fff(*xm): ... """find first false xpr in seq xpr ,msg, xpr, msg and yield pair"""
... it = iter(xm)
... for x in it:
... m = it.next()
... if not x: yield x, m; break
... >>> def test(x): ... assert not [t for t in fff(
...
... True, 'true msg',
... 1, 'one msg',
... 2==x, '2 eq x msg',
... 'xx', 'xx msg'
...
... )], 'Error: expr == %r, msg = %r'%t
... >>> test(2)
>>> test(3) Traceback (most recent call last):
File "<stdin>", line 1, in ?
File "<stdin>", line 7, in test
AssertionError: Error: expr == False, msg = '2 eq x msg'

Actually, why not just make a utility function "asserts" to do it:
>>> def asserts(*expr_msg_seq): ... """find first false expression value and assert it with paired message"""
... it = iter(expr_msg_seq)
... for x in it:
... m = it.next()
... if not x:
... assert x, '%r -> %r'%(x, m)
... >>> def test(x): ... asserts(
... True, 'true msg',
... 1, 'one msg',
... x, 'bool(x) is not True',
... x==2, '2 eq x msg',
... 'xx', 'xx msg'
... )
... >>> test(2)
>>> test(3) Traceback (most recent call last):
File "<stdin>", line 1, in ?
File "<stdin>", line 7, in test
File "<stdin>", line 7, in asserts
AssertionError: False -> '2 eq x msg' >>> test(0) Traceback (most recent call last):
File "<stdin>", line 1, in ?
File "<stdin>", line 7, in test
File "<stdin>", line 7, in asserts
AssertionError: 0 -> 'bool(x) is not True' >>> test(()) Traceback (most recent call last):
File "<stdin>", line 1, in ?
File "<stdin>", line 7, in test
File "<stdin>", line 7, in asserts
AssertionError: () -> 'bool(x) is not True' >>> test(type('foo',(),{'__nonzero__':lambda self:0})()) Traceback (most recent call last):
File "<stdin>", line 1, in ?
File "<stdin>", line 7, in test
File "<stdin>", line 7, in asserts
AssertionError: <__main__.foo object at 0x02EF17AC> -> 'bool(x) is not True' >>> test(type('foo',(),{'__nonzero__':lambda self:1})()) Traceback (most recent call last):
File "<stdin>", line 1, in ?
File "<stdin>", line 7, in test
File "<stdin>", line 7, in asserts
AssertionError: False -> '2 eq x msg' >>> test(type('foo',(),{'__nonzero__':lambda self:1, '__cmp__':lambda s,o:0})())


I doesn't shortcut, so you could get an exception in preparing the arg list for
a sequence like
asserts(
den !=0, 'denom must be zero',
num/den>5, 'better write it as assert num>5*den'
)
which would be safer as
assert den !=0, 'denom must be zero'
assert num/den>5 'better write it as assert num>5*den'

Not to mention side effects, but you shouldn't have those in asserts anyway.

Silliness ;-)

Regards,
Bengt Richter

Jul 18 '05 #17
Fábio Mendes <niels_bohr <at> uol.com.br> writes:

I never said that commas should mean line continuation (as a backslash).
It CAN be used as implicit line continuations in lot cases, (like
function arguments, for instance. This would be just one more case.


I'm not sure that I understand you correctly, but if you're saying that the
commas in a function argument list indicate an implicit line continuation, I
think this is probably not correct. It's the unclosed parentheses that indicate
the line continuation, not the commas -- this is why you can write a function
argument list across multiple lines, but it's also why you can write a tuple
across lines:
def f(x, .... y, z):
.... print x, y, z
.... f(1, 2, 3) 1 2 3 (x, .... y, z) = 1, 2, 3 print x, y, z 1 2 3

Note that just a trailing comma definitely does not mean a line continuation:
x, Traceback (most recent call last):
File "<interactive input>", line 1, in ?
NameError: name 'x' is not defined

I tried to write a tuple over multiple lines here, but (because commas do not
indicate line continuations), Python thinks I want to print the value of the
tuple containing x.

Of course, unclosed brackets work the same way as unclosed parentheses:
[x, .... y, z] = 1, 2, 3 print x, y, z

1 2 3

Steve

Jul 18 '05 #18
Fábio Mendes <ni********@uol.com.br> wrote:
So follow PEP 8's recommendation instead:

assert (
exp1 and
exp2 and
...
expn
), 'Errormsg'

I didn't know this would work for 'and/or' operators (even I've read the
style guide PEP!), sorry. It's not super beautiful, but I could live
happy with that :)


It works for the parentheses -- what operators are inside the
parentheses, including none at all, doesn't matter. A logical line
isn't finished until all kinds of parentheses are balanced.

I don't see the parentheses (which clarify the syntax issue you
mentioned in your first post) and 'and' as any uglier than the commas.
And having commas mean line continuation is out of the question.


I never said that commas should mean line continuation (as a backslash).
It CAN be used as implicit line continuations in lot cases, (like
function arguments, for instance. This would be just one more case.


Nope, comma can never be used as implicit line continuation in Python
(that's different from some other languages). The opened and yet
unclosed parentheses are what cause several physical lines to be part of
the same logical line -- not commas, nor other operator or punctuation.

Consider for example:

print ( 'some text'
'and some more'
'and yet more' )

look, ma: no commas (nor other punctuation nor operators, yet three
physical lines merge into just one logical line -- thanks to the
parentheses. This will print

some textand some moreand yet more

because adjacent string literals merge into one string literal (in
Python just like in C).

If you put commas there WITH the parentheses, you'd be printing out a
tuple. With the commas and WITHOUT the parentheses, syntax error.

You may be associating "commas continue lines" with "function arguments"
because function definitions and calls DO use parentheses, and separate
arguments with commas. But it's really not an ideal mental model.
Alex
Jul 18 '05 #19
Paul Rubin wrote:
"Raymond Hettinger" <vz******@verizon.net> writes:
Why do you need a statement for this?
IMO, a plain function will do the trick:
I do write such functions sometimes, but using a statement is more
natural. That's why the assert statement exists, for example.


I think 'assert' being a statement is on Guido's regrets list. exec and
print are on his regrets list: both should have been a function. I
think the same holds for assert, although I'm not sure.
statement is very great, and I find myself doing it all the time
thinking I'll clean it up later. So I think having a statement for
runtime checking would be in the correct spirit.


In my opinion, assert is almost useless. It can sometimes be useful for
debugging purposes, but beyond that, it isn't. The exception raised by
'assert' is always AssertionError. That is a major disadvantage, because
it's not specific. If a method I'm calling would raise an AssertionError
is some cases, and I want to catch it, I'm catching too much. Creating a
new exception-class and raising that one is better because of this.

I don't see the use of a statement like
"assert isinstance(message, basestring)". It's by far the most common
use of assert: some assertions about the types of the arguments. This is
at best redundant. In the case of warnings.py, it's followed by
re.compile(message, ...). Removing the assertion in this example would result
in three differences:
- The error raised would be TypeError, not AssertionError. Therefore
it's more specific and thus easier to catch.
- The error would me raised by the re module, not warnings module
- The error would be "first argument must be string or compiled
pattern" instead of "message must be a string". Therefore, the
assertion makes it impossible to pass a compiled pattern instead
of a string.

Duck typing eliminates the use of assert.

In my opinion, assert should be deprecated and then removed in Py3K:
assertions are redundant, unspecific, and conflict with the philosophy
of duck typing and EAFP.

What do others think of this?

Gerrit.

--
Weather in Twenthe, Netherlands 07/11 13:25:
12.0°C wind 3.6 m/s N (57 m above NAP)
--
In the councils of government, we must guard against the acquisition of
unwarranted influence, whether sought or unsought, by the
military-industrial complex. The potential for the disastrous rise of
misplaced power exists and will persist.
-Dwight David Eisenhower, January 17, 1961
Jul 18 '05 #20
Hello,

While I get what you are talking about - I think you are
missing the point of an assert function. If you document an assert
(which you should do) you are saying :- if you give me something which
follows these rules, then I will do this - thankyouverymuch.

In both Java and Eiffel, you have the option to compile the code
without the assert checking in - giving you a tight debug stuation and
a looser and faster run-time situation (as long as your code is tested
and robust). However Eiffel's require and ensure are Assert
statements on steroids!!

A classic text on this is by Bertrand Meyer - the inventor of
Eiffel. Although Eiffel's philosophy is very different than python's
it's a classic text. Here's a link to a short article about it :

http://archive.eiffel.com/doc/manual...logy/contract/

Cheers,

Neil

On Sun, 7 Nov 2004 14:02:09 +0100, Gerrit <ge****@nl.linux.org> wrote:
Paul Rubin wrote:
"Raymond Hettinger" <vz******@verizon.net> writes:
Why do you need a statement for this?
IMO, a plain function will do the trick:


I do write such functions sometimes, but using a statement is more
natural. That's why the assert statement exists, for example.


I think 'assert' being a statement is on Guido's regrets list. exec and
print are on his regrets list: both should have been a function. I
think the same holds for assert, although I'm not sure.
statement is very great, and I find myself doing it all the time
thinking I'll clean it up later. So I think having a statement for
runtime checking would be in the correct spirit.


In my opinion, assert is almost useless. It can sometimes be useful for
debugging purposes, but beyond that, it isn't. The exception raised by
'assert' is always AssertionError. That is a major disadvantage, because
it's not specific. If a method I'm calling would raise an AssertionError
is some cases, and I want to catch it, I'm catching too much. Creating a
new exception-class and raising that one is better because of this.

I don't see the use of a statement like
"assert isinstance(message, basestring)". It's by far the most common
use of assert: some assertions about the types of the arguments. This is
at best redundant. In the case of warnings.py, it's followed by
re.compile(message, ...). Removing the assertion in this example would result
in three differences:
- The error raised would be TypeError, not AssertionError. Therefore
it's more specific and thus easier to catch.
- The error would me raised by the re module, not warnings module
- The error would be "first argument must be string or compiled
pattern" instead of "message must be a string". Therefore, the
assertion makes it impossible to pass a compiled pattern instead
of a string.

Duck typing eliminates the use of assert.

In my opinion, assert should be deprecated and then removed in Py3K:
assertions are redundant, unspecific, and conflict with the philosophy
of duck typing and EAFP.

What do others think of this?

Gerrit.

--
Weather in Twenthe, Netherlands 07/11 13:25:
12.0°C wind 3.6 m/s N (57 m above NAP)
--
In the councils of government, we must guard against the acquisition of
unwarranted influence, whether sought or unsought, by the
military-industrial complex. The potential for the disastrous rise of
misplaced power exists and will persist.
-Dwight David Eisenhower, January 17, 1961
--
http://mail.python.org/mailman/listinfo/python-list

Jul 18 '05 #21

"Fábio Mendes" <ni********@uol.com.br> wrote in message
news:ma**************************************@pyth on.org...
I see two difficulties with it.

First, you can do the same thing (I think) with a
try block around a sequence of statements and
an assert in the except block. This means you
will need a fairly strong use case based on
convenience to add the syntax to the language.
You will have to show that it will be used a lot.
I meant expression instead of statement, sorry, that's my fault. It's a
minor cosmetic change I should say, only to avoid long grouping of
expressions with an 'and' operator. It's better expressed as: let the
commas take the place of 'and' in assertion verifications... Maybe that
could be extended to other parts of the language, but the only place I
think it would be useful is in assertion statements.


I see. That might have a syntactic difficulty, though, since the
comma is already in use as the tuple constructor operator.

John Roth
Thanks,
Fabio


Jul 18 '05 #22

"Gerrit" <ge****@nl.linux.org> wrote in message
news:ma**************************************@pyth on.org...
Paul Rubin wrote:
"Raymond Hettinger" <vz******@verizon.net> writes:
> Why do you need a statement for this?
> IMO, a plain function will do the trick:


I do write such functions sometimes, but using a statement is more
natural. That's why the assert statement exists, for example.


I think 'assert' being a statement is on Guido's regrets list. exec and
print are on his regrets list: both should have been a function. I
think the same holds for assert, although I'm not sure.
statement is very great, and I find myself doing it all the time
thinking I'll clean it up later. So I think having a statement for
runtime checking would be in the correct spirit.


In my opinion, assert is almost useless. It can sometimes be useful for
debugging purposes, but beyond that, it isn't. The exception raised by
'assert' is always AssertionError. That is a major disadvantage, because
it's not specific. If a method I'm calling would raise an AssertionError
is some cases, and I want to catch it, I'm catching too much. Creating a
new exception-class and raising that one is better because of this.


I see assert as a statement of an invariant: each and every time
I come here this *must* be true. I don't see it as a statement
of wishful thinking: when I come here, this should be true or
I'm going to have problems.

For me, an assert failing is a programing error in the caller,
not in the method with the assert! Trying to catch an
assert is a misuse of what the statement provides.

Besides which, you can always dress up an assert
with a string that can be printed, and then further
stick variables into that string with %.

John Roth
Jul 18 '05 #23
"John Roth" <ne********@jhrothjr.com> writes:
I see assert as a statement of an invariant: each and every time
I come here this *must* be true.
Yes, that was the intention of the assert statement. However, there's
a very great temptation to use it for a somewhat different purpose,
namely checking data validity. When there's a great temptation to
misuse some feature to do X when it's really intended for Y, that's a
sign that it's time to add an equally convenient feature intended for
doing X.
For me, an assert failing is a programing error in the caller, not
in the method with the assert! Trying to catch an assert is a misuse
of what the statement provides.


There's a slight non-sequitur there. Every large system contains
programming errors, and assert statements are a good way to detect the
errors. If an assert fails and isn't caught, the system crashes.
Crashing a running system on detection of the slightest programming
error is not always an acceptable thing to do. Sometimes you have to
log the error and try to recover from it, disable the feature where
the error happened until someone can figure out what went wrong, or
whatever; but not crash. So you need to be able to catch assert
failures.
Jul 18 '05 #24
Em Dom, 2004-11-07 Ã*s 08:56 +0000, Steven Bethard escreveu:
Fábio Mendes <niels_bohr <at> uol.com.br> writes:

I never said that commas should mean line continuation (as a backslash)..
It CAN be used as implicit line continuations in lot cases, (like
function arguments, for instance. This would be just one more case.


I'm not sure that I understand you correctly, but if you're saying that the
commas in a function argument list indicate an implicit line continuation, I
think this is probably not correct. It's the unclosed parentheses that indicate
the line continuation, not the commas -- this is why you can write a function
argument list across multiple lines, but it's also why you can write a tuple
across lines:
def f(x, ... y, z):
... print x, y, z
...


Now it makes sense to me... i thought that the commas was responsable for line continuation because this is how we usually separate the functions arguments and list/tuple/dictionary items. I never thought that this would work:
d = {'foo':

.... 'bar',
.... 'bar':
.... 'foo' }

But it works indeed ;)

I think my PEP is getting more and more nonsensical... I give up! Thanks for your advice guys,
Fabio

Jul 18 '05 #25
[...]

Nope, comma can never be used as implicit line continuation in Python
(that's different from some other languages). The opened and yet
unclosed parentheses are what cause several physical lines to be part of
the same logical line -- not commas, nor other operator or punctuation.
[...] You may be associating "commas continue lines" with "function arguments"
because function definitions and calls DO use parentheses, and separate
arguments with commas. But it's really not an ideal mental model.


You're right, that's a subtle misconception that don't give syntax
errors so I never realize to be the case ;-) I was writing multiple line
dictionaries like this:
dic = { \

.... key: value
.... key2: value2 }

The backslash is completely uncecessary (and ugly!). Thanks for
clarification,

-Fabio
Jul 18 '05 #26

"Paul Rubin" <http://ph****@NOSPAM.invalid> wrote in message
news:7x************@ruckus.brouhaha.com...
"John Roth" <ne********@jhrothjr.com> writes:
I see assert as a statement of an invariant: each and every time
I come here this *must* be true.


Yes, that was the intention of the assert statement. However, there's
a very great temptation to use it for a somewhat different purpose,
namely checking data validity. When there's a great temptation to
misuse some feature to do X when it's really intended for Y, that's a
sign that it's time to add an equally convenient feature intended for
doing X.
For me, an assert failing is a programing error in the caller, not
in the method with the assert! Trying to catch an assert is a misuse
of what the statement provides.


There's a slight non-sequitur there. Every large system contains
programming errors, and assert statements are a good way to detect the
errors. If an assert fails and isn't caught, the system crashes.
Crashing a running system on detection of the slightest programming
error is not always an acceptable thing to do. Sometimes you have to
log the error and try to recover from it, disable the feature where
the error happened until someone can figure out what went wrong, or
whatever; but not crash. So you need to be able to catch assert
failures.


I think I didn't say it quite well enough. Of course you catch
assert errors, but you classify them the same as non-recoverable
environmental errors: you scrub whatever unit of work you were
working on, log the error and try to recover the application so
the user can continue.

I think we're in agreement that what you don't want to do
is try to catch and recover from a specific assert error.

John Roth

Jul 18 '05 #27
Gerrit <ge****@nl.linux.org> wrote in message news:<ma**************************************@pyt hon.org>...
Paul Rubin wrote:
"Raymond Hettinger" <vz******@verizon.net> writes:
Why do you need a statement for this?
IMO, a plain function will do the trick:
I do write such functions sometimes, but using a statement is more
natural. That's why the assert statement exists, for example.


I think 'assert' being a statement is on Guido's regrets list. exec and
print are on his regrets list: both should have been a function. I
think the same holds for assert, although I'm not sure.


I don't recall seeing assert on that list. Unlike print and exec,
what assert does can't be done by a function.

statement is very great, and I find myself doing it all the time
thinking I'll clean it up later. So I think having a statement for
runtime checking would be in the correct spirit.


In my opinion, assert is almost useless. It can sometimes be useful for
debugging purposes, but beyond that, it isn't. The exception raised by
'assert' is always AssertionError. That is a major disadvantage, because
it's not specific.


Actually it is, if you use assert correctly. I'll get to that.

If a method I'm calling would raise an AssertionError
is some cases, and I want to catch it, I'm catching too much. Creating a
new exception-class and raising that one is better because of this.
If you use assert correctly, you either wouldn't want to catch
AssertionError, or you'd want to catch it at a rather high level and
print a message about a bug in the program.

I don't see the use of a statement like
"assert isinstance(message, basestring)". [snip]

Generally speaking, this is an incorrect use of assert. I don't
approve of this use of assert.

The proper use of assert is to declare that a certain condition is
impossible. That is, if the program is bug-free, this condition will
never happen. An assertion error should never be raised unless
there's a bug in the program.

Here's a ridiculous, and incorrect, but illustrative, example of its
proper use:

def f(y):
x = y*y
assert x >= 0

As we know, multiplying a real number by itself always produces a
positive number (for the sake of argument, let's ignore the fact that
y could be a complex number). Thus, is it impossible for x to be
negative. Impossible, that is, unless there's a bug. The assert
statement declares this to be an impossible condition. If this
condition does not hold, it can't be bad input. It's a bug.
Obviously, this is a silly example, but real world examples aren't so
silly.

Because it's an "impossible" condition, it only needs to be checked in
debugging builds. This is where the magic of the assert statement
comes in: in an optimized build, the assertion is not checked. Thus
it's an optimiztion. If you change assert into a function, Python can
no longer optimize the assertion away, because the function argument
is always evaluated.

This however, raises a question: is it a premature optimization? I
would say yes and no. For simple assertion, like assert x >= 0, the
optimization is premature and probably not worth justifying an assert
statement. However, I still like having it, just to document that the
condition being checked is intended to be an impossible condition, as
opposed to bad input or an operating system error.

However, there are some impossible conditions that are simply not
premature optimizations by anyone's definition. Let me show you an
example:

def some_public_function(tree1, tree2):
assert one-to-one(tree1,tree2)
...

In this case, I have two tree heirarchies which the program is to keep
1:1 at all time (i.e., for every node in tree1, there is a
corresponding node in tree2). There are hundreds of functions
operating on both trees, and all of them have to make sure to update
both hierarchies. If there is any exit point of a public function
where these trees are not one-to-one, then it's a bug.

The problem is, checking the whole hierarchy every time you call a
public function is simply too expensive for production code. An
assert statement lets you optimize this call away, and very
conveniently. I feel that power justifies the existence of assert.

Assert statements have found many, many bugs in my larger projects, so
I would be very sad to see them go away. HOWEVER, in the end, I could
easily live without it. Simple assertions don't cost much to check in
production code. Expensive assertions I usually put in a function
anyways, so I can optimize it away by simply not calling it unless a
debug flag is set.

In my opinion, assert should be deprecated and then removed in Py3K:
assertions are redundant, unspecific, and conflict with the philosophy
of duck typing and EAFP.

What do others think of this?


I don't want to see it disappear because it has valid uses.

I think it would be wise to discourage the use of assert for purposes
it wasn't intended for, such as the example you gave.

IMO, the best way to do this is to have assertion OFF by default.

The way Python is set up now is to have a default mode and optimized
mode, the optimized mode not running asserts. I would change that. I
suggest that Python should instead have a default mode and a debugging
mode, and that assertions should only be checked in debugging mode.
Ordinary Python runs, without a -g flag, would simply ignore assert
statements.
--
CARL BANKS
Jul 18 '05 #28
[Fábio Mendes]
I think my PEP is getting more and more nonsensical... I give up!


LOL. The PEP is the same. It is it's author's world view that has changed ;-)
Raymond

Jul 18 '05 #29

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

9
2009
by: Dan Perl | last post by:
Is there a mechanism or an idiom for adding code for debugging so that it can easily be removed in the production code? I am thinking of something similar to the C/C++ preprocessor statements with...
12
2775
by: Siemel Naran | last post by:
What is a good idiom for handling a lazy object? I see 2 good possibilities. Any more, any comments? Which way do people here use? (1) class Thing { public: Thing(double x, double y) :...
0
6904
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
7034
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
7076
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
1
6732
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...
0
5324
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing,...
1
4768
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new...
0
2976
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
1
558
muto222
php
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.
0
174
bsmnconsultancy
by: bsmnconsultancy | last post by:
In today's digital era, a well-designed website is crucial for businesses looking to succeed. Whether you're a small business owner or a large corporation in Toronto, having a strong online presence...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.