Re: [Python-ideas] PEP 8 update on line length

2019-02-22 Thread Juancarlo Añez
On Fri, Feb 22, 2019 at 5:10 PM Greg Ewing 
wrote:

> I would say it the other way around. Once you've reduced the complexity
> of a line to something a human can handle, *most* of the time 80 chars
> is enough.
>

+1

It has been known for a very long time.

These are *old *books that talk about *refactoring* (the word wasn't used
then) of complex code (assigning subexpressions to variables, or extracting
code into functions, reverting conditionals, etc.), not for line length,
but for understandability, yet resulting nevertheless in much shorter lines:

   - Software Tools (also Software Tools in Pascal), Kernighan and Plauger,
   1976
   https://smile.amazon.com/Software-Tools-Brian-W-Kernighan/dp/020103669X
   - Code Complete (also the second edition), Steve Mc Connell, 1993,
   https://smile.amazon.com/Software-Tools-Brian-W-Kernighan/dp/020103669X

I do make an exception in that after taking 8 spaces of indentation to
write the implementation of a method in Python, the sweet spot is more
around 100 chars.

-- 
Juancarlo *Añez*
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Type hints for functions with side-effects and for functions raising exceptions

2019-02-22 Thread Chris Angelico
On Sat, Feb 23, 2019 at 9:14 AM Kyle Lahnakoski  wrote:
> Let me call this pattern the Catch-It-Name-It-Chain-It-Raise-It (CNCR)
> pattern
>
> There are a few reasons for this.
>
> 1. I can add runtime values to the exception so I get a better sense of
> the program state without going to the debugger:  `error("some
> description", {"url": url}, cause=e)`
> 2. I prevent exception leakage; I have no idea the diversity of
> exceptions my code can raise, so I CNCR.
> 3. Every exception is it's own unique type; I can switch on the message
> if I want (I rarely do this, but it happens, see below)
>
> Can Python provide better support for the CNCR pattern? If it is
> lightweight enough, maybe people will use it, and then we can say
> something useful about the (restricted) range of exceptions coming from
> a method:

The CNCR pattern, if used repeatedly, will quickly create a long chain
of exceptions, where each exception represents one function call.
Python already has very good support for seeing the function call
history that led to the exception - it's called a traceback. You even
get the full function locals as part of the exception object... and it
requires no code whatsoever! Simply allowing exceptions to bubble up
will have practically the same benefit.

ChrisA
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Type hints for functions with side-effects and for functions raising exceptions

2019-02-22 Thread Kyle Lahnakoski

On 2019-02-21 03:09, Christopher Barker wrote:
>
> But yes, there is no (easy) way to distinguish an Exception raised by
the function you called, and one raised somewhere deeper that.
>
> And I have been bitten by that more than once. It makes "Easier to ask
forgiveness than permission" kind of tricky.

> And Exception handling is messy -- the point made by the OP, I'm not
sure there's a better way to do it.


It seems to me that exception *classes* are hardly ever required. If two
methods raise the same exception type, then I contend that they are
actually throwing two different types of errors (as evidenced by the
difference in the message). Instead, I suggest every method emits its
own exception type.

By demanding support for a plethora of exception types, at least as many
as there are methods, then we may have a different way of looking at
exceptions: The first conclusion is, it is too expensive to make classes
for every exception type, rather, exception type should be defined by
the message.


Exception handling is messy. I find most of my Python methods look like:

    | def my_method():
    | try:
    | # do something
    | except Exception as e:
    | error("some description", cause=e)

I am not using Python3 everywhere yet, so maybe it should read like:

    | def my_method():
    | try:
    | # do something
    | except Exception as e:
    | raise Exception("some description") from e


Let me call this pattern the Catch-It-Name-It-Chain-It-Raise-It (CNCR)
pattern  

There are a few reasons for this.

1. I can add runtime values to the exception so I get a better sense of
the program state without going to the debugger:  `error("some
description", {"url": url}, cause=e)`
2. I prevent exception leakage; I have no idea the diversity of
exceptions my code can raise, so I CNCR.
3. Every exception is it's own unique type; I can switch on the message
if I want (I rarely do this, but it happens, see below)

Can Python provide better support for the CNCR pattern? If it is
lightweight enough, maybe people will use it, and then we can say
something useful about the (restricted) range of exceptions coming from
a method:

A context manager, a `with` block, could do this:  

    | def my_method():
    | with Explanation("some description"):
    | # do something

I propose a simple line, which effectively defines a try block to the
end of the current code block. Call it the `on-raises` syntax:

    | def my_method():
    | on Exception raises "some description"
    | # do something

It is better than the `with` block because:

* it does not put code in the happy path
* it has less indentation
* we can conclude "some description" is the only exception raised by
this method  

The `on-raises` need not start at the beginning of a code block, but
then we can say less about what exceptions come out of `my_method`:

    | def my_method():
    | # no exception checks here
    | on Exception raises "some description"
    | # do something

Since `on-raises` can be used in any code block, we can save some
indentation. Instead of

    | def my_method():
    | with some_file:
    | try:
    | # do something
    | except Exception as e:
    | raise Exception("some description") from e

we have

    | def my_method():
    | with some_file:
    | on Exception raises "some description"
    | # do something

of course we can have nested `on-raises`,

    | def my_method():
    | on Exception raises "bigger problem"
    | with some_file:
    | on Exception raises "some description"
    | # do something

Plus we know only "bigger problem" exceptions can be raised.

The above is the same as:
    | def my_method():
    | try:
    | with some_file:
    | try:
    | # do something
    | except Exception as e:
    | raise Exception("some description") from e
    | except Exception as e:
    | raise Exception("bigger problem") from e

in the rare case we actually want to deal with an exception, we revert
back to trusty old try/except:

    | def my_other_method():
    | on Exception raises "some other description"
    | try:
    | my_method()
    | except "some description" as e:
    | # I know how to handle this case
    | return

which is the same as:

    | def my_other_method():
    | try:
    | my_method()
    | except Exception as e:
    | if "some description" in e:
    | # I know how to handle this case
    | return
    | error("some other description", cause=e)
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] PEP 8 update on line length

2019-02-22 Thread Greg Ewing

Christopher Barker wrote:


(And did they ever stop to wonder why those old terminals
standardized on 80 columns?)


Probably because IBM decided on 80 columns for their punched cards.
And that probably didn't have anything to do with a readable width
for text. Nobody used computers for word processing back then.
In fact punched cards predate computers altogether, originally
being developed for electromechanical accounting and record keeping
machines.

I’m 
pretty sure the old tractor feed paper terminal I first learned to code 
on was a lot more than 80 char wide.


Line printers were traditionally 120 chars wide, but again that had
nothing to do with text. It was so that accountants could print reports
with a ridiculously large number of columns of figures.

How many of us still type on QWERTY keyboards? Even on a phone, like I 
am now.


Once you're used to qwerty, anything else is a nuisance, even if you're
not touch typing on it. A place I park at recently installed machines
you enter your car's license number into. The keyboard has the letters
in alphabetical order, presumably because someone thought it would be
"easier". But nowadays I suspect it just makes it harder for most
people!

“Typesetters hundreds of years ago used less than 80 chars per line, so 
that’s what we should do for Python code now” is a pretty weak argument.


But that's not the entire argument -- the point it is that typesetters
had the goal of making lines of text readable, which is similar (if not
quite the same) as the goal of making lines of program code readable.
It's a lot closer than, for example, the goal of fitting in an
accountant's spreadsheet.

Agreed — you can have too much complexity in 80 char. Which is why I 
think the 80 char limit is about what fits on a screen, not complexity.


I would say it the other way around. Once you've reduced the complexity
of a line to something a human can handle, *most* of the time 80 chars
is enough.

There will be exceptions, but as long as the exceptions are rare, making
your editing window any wider will mostly just waste screen space.

--
Greg
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Type hints for functions with side-effects and for functions raising exceptions

2019-02-22 Thread Juancarlo Añez
On Thu, Feb 21, 2019 at 11:32 PM Chris Angelico  wrote:

> On Fri, Feb 22, 2019 at 2:27 PM Juancarlo Añez  wrote:
> > Then, if exceptions are going to be part of a type, there should be a
> way to express the semantics of them (like in Eiffel), so
> stack.pop();stack.push(x) doesn't have to catch StackFullException.
> >
>
> That assumes atomicity. If you want an atomic "replace top of stack"
> that can never raise StackFullException, it's probably best to express
> it as stack.replacetop(x) rather than having something that might be
> interrupted.
>

Ah! What to do with an exception in a concurrent context? Abort, or retry
after a while?


> People do dumb things with exceptions, yes. Why does this mean that
> they are bad? I don't understand this. Exception handling (and stack
> unwinding) gives an easy and clear way to refactor code without having
> to daisychain error handling everywhere. How is throwing that away
> going to help people write better code?
>

For programs that are recursive or multi-layered, exceptions are a clean
and efficient way to unwind.

This PEG parser generator I wrote was made possible because Python
exceptions are semantically clean and very efficient:
https://github.com/neogeny/TatSu/blob/master/tatsu/contexts.py


> But then, Golang also decided that Unicode wasn't necessary, and we
> should all deal with UTF-8 encoded byte sequences instead of text
> strings, so I'm fairly sure there are no ten foot barge poles long
> enough for me to touch it with. There are languages that have problems
> because of history (*cough*JavaScript*cough*), but for a new language
> to make multiple poor decisions just means it's one to avoid.
>

The quest for a programming language in which _"anyone"_ can program,
_without_ making mistakes, has never ended, and probably never will.

"Alexa! Please write the software for a new Internet email system that
overcomes the limitations of the current one!"


Sometimes staying away is not an option.

-- 
Juancarlo *Añez*
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] Type hints for functions with side-effects and for functions raising exceptions

2019-02-22 Thread Chris Angelico
On Sat, Feb 23, 2019 at 5:32 AM Juancarlo Añez  wrote:
> On Thu, Feb 21, 2019 at 11:32 PM Chris Angelico  wrote:
>>
>> On Fri, Feb 22, 2019 at 2:27 PM Juancarlo Añez  wrote:
>> > Then, if exceptions are going to be part of a type, there should be a way 
>> > to express the semantics of them (like in Eiffel), so 
>> > stack.pop();stack.push(x) doesn't have to catch StackFullException.
>> >
>>
>> That assumes atomicity. If you want an atomic "replace top of stack"
>> that can never raise StackFullException, it's probably best to express
>> it as stack.replacetop(x) rather than having something that might be
>> interrupted.
>
> Ah! What to do with an exception in a concurrent context? Abort, or retry 
> after a while?

You mean in a situation where another thread might be pushing/popping
on the same stack? That's up to you. Exception handling works exactly
the same way with multiple threads as it does with a single thread;
each context has a call stack.

Things are a bit more complicated with other forms of concurrency, but
at the point where there is an execution context again, that's where
exceptions can start bubbling again. That's how generators work, for
instance.

ChrisA
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] PEP 8 update on line length

2019-02-22 Thread Jonathan Fine
Raymond Hettinger posted a helpful example to this list. Here, I run
his example, and a variant, through https://black.now.sh

Raymond
class Frabawidget:

@wozzle.setter
def wibble(self, woozle):
if not (self.min_woozle < woozle < self.max_woozle):
raise ValueError(f"Expected woozle to be between
{self.min_woozle} and {self.max_woozle}")
self._wozzle = normalize(woozle)

black.py
class Frabawidget:
@wozzle.setter
def wibble(self, woozle):
if not (self.min_woozle < woozle < self.max_woozle):
raise ValueError(
f"Expected woozle to be between {self.min_woozle} and
{self.max_woozle}"
)
self._wozzle = normalize(woozle)

Raymond variant
class Frabawidget:

@wozzle.setter
def wibble(self, woozle):
if not (self.min_woozle < woozle < self.max_woozle <
self.super_max_value) and do_this_or_that_():
raise ValueError(f"Expected woozle to be between
{self.min_woozle} and {self.max_woozle}")
self._wozzle = normalize(woozle)

black.py
class Frabawidget:
@wozzle.setter
def wibble(self, woozle):
if (
not (
self.min_woozle
< woozle
< self.max_woozle
< self.super_max_value
)
and do_this_or_that_()
):
raise ValueError(
f"Expected woozle to be between {self.min_woozle} and
{self.max_woozle}"
)
self._wozzle = normalize(woozle)

(By the way, I had to add the 'wibble' to the code above, to avoid a
syntax error.)
-- 
Jonathan
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] PEP 8 update on line length

2019-02-22 Thread Dan Sommers

On 2/21/19 10:33 PM, Steven D'Aprano wrote:


(And did they ever stop to wonder why those old terminals
standardized on 80 columns?)


Punch cards?

https://softwareengineering.stackexchange.com/questions/148677

There's an ensuing discussion regarding the history of the
size/shape of the punch card, too.

Dan
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] PEP 8 update on line length

2019-02-22 Thread Christopher Barker
>
>
> Chris, the convention to limit text to somewhere around 60-80 characters
> predates old terminals by *literally centuries*.


Not for code, it doesn’t— and centuries ago, there were other technical
issues on play for papermaking, hand writing, and typesetting.

>
(And did they ever stop to wonder why those old terminals
> standardized on 80 columns?)


CRTs were small and low resolution?

A 200 char line would have been very expensive back in the day, and I’m
pretty sure the old tractor feed paper terminal I first learned to code on
was a lot more than 80 char wide.

But now that you mention it, I suspect the 80 char punch cards had an
influence.

How many of us still type on QWERTY keyboards? Even on a phone, like I am
now.

The point is that we conform to s lot of conventions without re-adding
whether the original reasons for those conventions apply. And no one on
this thread has cited a study about optimum line length for readability of
code. I have no idea if that’s ever been done — but that is the question at
hand.

“Typesetters hundreds of years ago used less than 80 chars per line, so
that’s what we should do for Python code now” is a pretty weak argument.

> Go back and read the thread.

I have read the thread. And Raymond made a pretty good argument for why, in
some cases, a shorter line limit is a problem— and I have had much the same
experience.


and the nuisance value of splitting a conceptual
> line of code over multiple physical lines.


I think one key question is whether it’s a nuisance, or actually makes some
code harder to read.

>
> 1. 79 characters is *very generous* for most lines of code;


I’ve found a common exception for this is string literals and trailing
comments.

And I often prefer 80+ char trailing comments to an extra comment line.

2. When a single line goes beyond 80 columns, it often wants to go a
> long way beyond.


Often True, but I’ve found setting my linter to 95 char makes a big
difference in my code


> Opinion: we really shouldn't be encouraging people to write long complex
> lines of code.


Agreed — but as you point out, those are often MUCH longer, so pushing the
line limit to < 100 chars doesn’t really change that.

4. But one notable exception to this is the case where you have a long
> format string, often passed to "raise Exception",

...

> These are often indented four or five levels deep, and they really are a
> pain-point.


Oh yeah, that was Raymond’s point, and I concurred and emphasized it.

>
> Opinion: common sense should prevail here. If you have a line "raise
> ValueError(...)" which would reach 80 or even 90 characters, don't let
> PEP 8 alone tell you otherwise.


Yup - the trick here is that it’s hard to define clearly in a style guide,
and even harder in a linter.

One issue with all this is that there’s been a move toward automated
enforcement (or checking) of style. Which I think is an overall good thing,
but then it’s hard to allow judgement as well.

But if you have a more substantial code that exceeds 80 columns, that's
> a code smell and you ought to think long and hard before breaking it.


My reading of your points above is that the really smelly code is well over
80 chars, so having a slightly larger limit would work fine as well.


Proposal:
>
> - keep PEP 8's current recommendation;


As long as that includes the “ you can raise it to up to 100 char, sure :-)

>
> - but remind people that the rule can be relaxed for lines that are
> conceptually simple, such as the "raise Exception(...)" pattern;


It would be nice, if possible, to clearly define this relaxation.

- and also remind people that long *complex* lines are an anti-pattern.
> Such complex lines can be improved by splitting them over multiple
> lines, and should be.


Not sure that’s needed, but why not?

>
> That effectively says "any amount of complexity is OK in a single line,
> so long as it remains below X columns". I'd rather people look at the
> line and decide "this is too complex, split it" or "it's just a format
> string (or whatever), let it be".


Agreed — you can have too much complexity in 80 char. Which is why I think
the 80 char limit is about what fits on a screen, not complexity.

-CHB
-- 
Christopher Barker, PhD

Python Language Consulting
  - Teaching
  - Scientific Software Development
  - Desktop GUI and Web Development
  - wxPython, numpy, scipy, Cython
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/


Re: [Python-ideas] PEP 8 update on line length

2019-02-22 Thread James Lu
A general rule of thumb is, if Python feels inconvenient or awkward, you’re 
doing something wrong. 
___
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/