So I do not have extensive experience with mypy but I don't see how it would help.  The entire issue that is that `str` is an instance of  `Iterable[str]` so how is mypy going to catch my error of passing a single string instead of an iterable of strings to a function?

However the ability to distinguish between `str` and `Iterable[str]` is important.  I often write functions that operate on scalar or iterable of scalar and I always need to special case `str`.  Now you might argue that my life would be simplified if I required everything just be an iterable and you would be right.  However, it would still leave me with strange errors when passing single strings and would decrease usability.  Consider the behavior of `__slots__`, I for one think its great that `__slots__ = "foo"` does what it does.  I think it would be bad from usability standpoint to require a trailing comma, even if it would simplify the life of the interpreter.

I like the idea of an `AtomicString` but it doesn't really help unless IO and string literals return `AtomicString` instead of `str` (which is just as breaking as changing `str`).

I agree that noisy is broken and that a warning that never becomes an error is probably a bad idea.

While I am firmly in the camp that this is a problem I am not sure if its a problem that should be fixed.  Any solution will break code, there is no way around it. However, I think one possible solution (that has it own set of draw backs) would be to simply not register `str` as subclass of `Iterable`.  This would allow for the following pattern:

```
if isinstance(obj, Iterable):
  # iterable case
else:
  # scalar case
```

Where currently the following is required:

```
if isinstance(obj, Iterable) and not isinstance(obj, (str, bytes)):
  # iterable case
else:
  # scalar case
```

Yes this would break code, but it would break a lot less code than actually changing the behavior of `str`.

On Mon, Feb 24, 2020 at 3:16 PM Dominik Vilsmeier <dominik.vilsmeier@gmx.de> wrote:
I agree, a warning that is never converted to an error indicates that
this is more about style than behavior (and in that sense it is use case
specific). It would also be annoying for people that intentionally
iterate over strings and find this a useful feature.

So this sounds more like the job for a linter or, because it's dealing
with types, a type checker. So what about the compromise that for
example mypy added a flag to treat strings as atomic, i.e. then it would
flag usage of strings where an iterable or a sequence is expected. Would
that solve the problem?

On 24.02.20 23:31, Paul Moore wrote:
> On Mon, 24 Feb 2020 at 20:13, Alex Hall <alex.mojaki@gmail.com> wrote:
>>> Conversely, I can't remember a case where I've ever accidentally
>>> iterated over a string when I meant not to.
>> Do you ever return a string from a function where you should have returned a list containing one string? Or similarly passed a string to a function? Forgotten to put a trailing comma in a singleton tuple? Forgotten to add .items() to `for key, value in kwargs:`?
> Not that I remember - that's what I said, basically. No, I'm not
> perfect (far from it!) but I don't recall ever hitting this issue.
>
>>> compelling arguments are typically
>>> around demonstrating how much code would be demonstrably better with
>>> the new behaviour
>> That represents a misunderstanding of my position. I think I'm an outlier among the advocates in this thread, but I do not believe that implementing any of the ideas in this proposal would significantly affect code that lives in the long term. Some code would become slightly better, some slightly worse.
> I beg to differ.
>
> * Code that chooses to use `.chars()` would fail to work on versions
> of Python before whatever version implemented this (3.9? 3.10?). That
> makes it effectively unusable in libraries for years to come.
> * If you make iterating over strings produce a warning before
> `.chars()` is available as an option for any code that would be
> affected, you're inflicting a warning on all of that code.
> * A warning that will never become an error is (IMO) unacceptable.
> It's making it annoying to use a particular construct, but with no
> intention of ever doing anything beyond annoying people into doing
> what you want them to do.
> * A warning that *will* become an error just delays the problem -
> let's assume we're discussing the point when it becomes an error.
>
> As a maintainer of pip, which currently still supports Python 2.7, and
> which will support versions of Python earlier than 3.9 for years yet,
> I'd appreciate it if you would explain what pip should do about this
> proposed change. (Note: if you suggest just suppressing the warning,
> I'll counter by asking you why we'd ever remove the code to suppress
> the warning, and in that case what's the point of it?)
>
> And pip is an application, so easier. What about the `packaging`
> library? What should that do? In that case, modifying global state
> (the warning config) when the library is imported is generally
> considered bad form, so how do we protect our users from this warning
> being triggered by our code? Again, we won't be able to use `.chars()`
> for years.
>
> Boilerplate like
>
> if sys.version_info >= (3, 9):
>      def chars(s):
>          return s.chars()
> else:
>      def chars(s):
>          return s
>
> would be an option, but that's a lot of clutter for every project to
> add for something that *isn't a problem* - remember, long-running,
> well-maintained libraries with a broad user base will likely have
> already flushed out any bugs that might result from accidentally
> iterating over strings. And these days, projects often use mypy which
> will catch such errors as well. So this is literally useless
> boilerplate for them.
>
>> My concern surrounds the user experience when debugging code that accidentally iterates over a string. So it's impossible for me to show you code that becomes significantly better because that's not what I'm arguing about, and it's unfair to say that quoting people who have struggled with these bugs is not evidence for the problem.
> OK. That's a fair point. But why can't we find other approaches? Type
> checking with mypy would catch returning a string when it should be a
> list of strings. Same with all of your other examples above. How was
> your experience suggesting mypy for this type of problem? I suspect
> that, as you are talking about beginners, you didn't inflict anything
> that advanced on them - is there anything that could be done to make
> mypy more useful in a beginner context?
>
>> I would like to reiterate a point that I think is very important and many people seem to be brushing aside. We don't have to *break* existing code. We can get a lot of value, at least in terms of aiding debugging, just by adding a warning.
> Years of experience maintaining libraries and applications have
> convinced me that warnings can cause as much "breakage" as any other
> change. Just saying "you can suppress them" doesn't make the problem
> go away. And warnings that are suppressed by default are basically
> pointless, as people just ignore them. That's not to say that warnings
> are useless - just that introducing *new* warnings needs to be treated
> just as seriously as any other change.
>
> Paul
> _______________________________________________
> Python-ideas mailing list -- python-ideas@python.org
> To unsubscribe send an email to python-ideas-leave@python.org
> https://mail.python.org/mailman3/lists/python-ideas.python.org/
> Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/5IIVW5OTKIT2EDD2N6JBGABGRENYNBTX/
> Code of Conduct: http://python.org/psf/codeofconduct/
_______________________________________________
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-leave@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/ZWHXOCOT5J4DEZNBLTXU73ONQQPIS2AC/
Code of Conduct: http://python.org/psf/codeofconduct/