Type hinting a non-generator (non-consumable) iterable - python-3.x

I'd like to type hint a function like this:
from types import Iterable
def func(thing: Iterable[str]) -> None:
for i in range(10):
for x in thing:
do_thing(x)
PyCharm will (correctly) let me get away with passing in a generator to this function, but I want to type hint it in a way that it won't allow me to, while still accepting other iterables.
Using Sequence[str] isn't an option, iterables like KeyView aren't sequences, but I would still like to be able to include them.
Someone mentioned using a Union with a Sequence + KeyView, which would work, but I was wondering if there was a more elegant and universal solution
Of course, I could just convert thing to a list no matter what, but I'd rather just have this function type hinted correctly.
Using Python 3.7

Unfortunately I think this is just not possible with Python's type system.
Straight from Guido (source):
Our type system doesn't allow you to express that -- it's like asking for any Animal except Cat. Adding an "except" clause like that to the type system would be a very difficult operation.
Since there's no solution, I'm going to close this as "won't fix".
His suggestion:
Yeah, the practical solution is Sequence|Set|Mapping. The needed negation is years off.

Related

How can I pass a set of instances to a function or predicate in Alloy Analyzer's Evaluator?

BLUF: I have a predicate which takes as arguments an instance of a signature and a set of instances of the same signature. Upon generating instances of the model, I'd like to pass instances of the signature to the predicate, but am at a loss for how to pass a set of instances, if it is even possible.
Alloy's Evaluator does not appear to be well-documented, unless I've missed it. I have Daniel Jackson's book, have done the tutuorial, and found various other resources online, but no one really seems to address how to use the Evaluator.
I've tried notation like:
myPred[instance$0,set(instance$1,instance$2)]
and
myPred[instance$0,set[instance$1,instance$2]]
and
myPred[instance$0,(instance$1,instance$2)]
and
myPred[instance$0,[instance$1,instance$2]]
The Evaluator doesn't like any of them. Is it possible to pass a set of instances? If so, how do I do it? Thanks for the help!
So, in usual fashion for me, almost as soon as I asked the question, I realized the answer (or at least a way to do what I wanted to). I simply used the union operator "+" to pass the set.
myPred[instance$0, instance$1 + instance$2]
Sorry for the inconvenience, but maybe this will help someone else!

What's the difference between an instruction and a function?

I have just started learning Python. I came across del instruction. I could not understand difference between an instruction and a function like len(). I googled it but could not find the answer. Apologies if this question sounds childish.
Things like del, def, class, lambda, with, for, while, etc. are all similar in that they are essentially special cases. They all have specifically-defined behavior, but that behavior is hardcoded into the python interpreter.
In the case of def, that behavior is to parse the following text in a certain way - as a function. Similar for lambda, as a lambda function, and for class, as a class.
In the case of with, the behavior is to take an argument, call .__enter__() on it, and assign the result to a name that's given after the as keyword. With for, it's the opposite - define the name before the in keyword, and then call .__iter__() on whatever's after, assigning each item in turn to the name.
del is similar, in that it has a built-in function - it removes the object from the current namespace. That's just what it does, hardcoded behavior of the interpreter. There are a couple of special cases baked in for iterable objects, in which case (IIRC) the compiler calls .__delitem__() on it.
Functions are a specific type of object with a specific programmer-defined behavior. They're defined with the def instruction.

Python Typing with Exception Handling

The following code is stored in a file called sample.py.
import re
from typing import Optional, Tuple
 
def func(path: str) -> Optional[Tuple[str, str]]:
    regex = re.compile(r"/'([^/']+?)'/'([^/']+?)'")
    try:
        return regex.match(path).groups()
    except AttributeError:
        return None
The Mypy Python linter throws the following error when analyzing the code:
sample.py:8: error: Incompatible return value type (got "Union[Sequence[str], Any]", expected "Optional[Tuple[str, str]]")
sample.py:8: error: Item "None" of "Optional[Match[str]]" has no attribute "groups"
While regex.match(path).groups() may return a None type, which does not have a groups attribute, the resulting exception is handled and the handling is specified in the return type. However, Mypy does not seem to understand that the exception is being handled. As far as I understand Optional[Tuple[str, str]] is the correct return type and Mypy instead insists that the less specific type Union[Sequence[str], Any] is correct . What is the proper way to use exception handling with Python typing? (Please, note that I am not asking for alternate ways to write the code without using exception handling. I am just trying to provide a minimal and complete example, where Python type checkers do not behave as  I would expect with exception handling.)
Mypy does not really understand exceptions on a deep level -- in this case, does not understand that since you're catching the AttributeError, it can ignore the "what if regex.match(path) is None?" case.
More generally, the fundamental assumption mypy makes is that when you have some object foo with type Union[A, B] and you do foo.bar(), both types A and B have a bar() method.
If only one of those types have a bar() method, you'll need to do one of several things:
Give mypy sufficient information to narrow down the union to just one of the relevant types before performing the attribute access. For example, isinstance checks, x is not None checks...
Acknowledge that you are attempting to do something the type checker does not understand and settle for suppressing the generated error. For example, you could cast the type, add on a # type: ignore comment, find a way of making foo be the dynamic Any type...
Find a way of redesigning your code to side-step this issue altogether.
(In this particular case, I suppose another alternative might be to submit a pull request to mypy adding support for this pattern. But I'm not sure if this is really feasible: changing any kind of fundamental assumption is difficult work on multiple dimensions.)
Similarly, Mypy also does not understand regexes on a deep level -- e.g. doesn't try and analyze your regex to determine how many groups you'll get and so won't understand your particular regex happens to match strings with exactly two groups. The best it can do is assert that the group will return some unknown number of strings -- hence the type Sequence[str] instead of Tuple[str, str].
This sort of limitation is pretty common in type checkers in general, actually: most type systems in mainstream languages don't really support a way to predicate a return type based on the contents of any actual values passed in. Such type systems (dependent type systems, refinement type systems...) are pretty difficult to implement and often have a steep learning curve for end users.
However, it would be easier to make mypy support this on a best-effort basis by writing a mypy plugin, if you're up for it. Specifically, try taking a look at get_method_hook() and get_function_hook().

Python typing, pickle and serialisation

I've started learning the typing system in python and came across an issue in defining function arguments that are picklable. Not everything in python can be pickled, can I define a type annotation that says "only accept objects that can are picklable"?
At first it sounds like something that should be possible, similar to Java's Serializable but then there is no Picklable interface in python and thinking about the issue a little more it occurs to me that pickling is an inherently runtime task. What can be pickled lists a number of things that can be pickled, and it's not difficult to imagine a container of lambda functions which would not be picklable, but I can't think of a way of determining that before hand (without touching the container definition).
The only way I've come up with is to define something like a typing.Union[Callable, Iterable, ...] of all the things listed in What can be pickled but that does not seem like a good solution.
This issue on github partially answers the question, although the issue is specifically related to json not pickle but the first answer from Guido should still apply to pickle
I tried to do that but a recursive type alias doesn't work in mypy right now, and I'm not sure how to make it work. In the mean time I use JsonDict = Dict[str, Any] (which is not very useful but at least clarifies that the keys are strings), and Any for places where a more general JSON type is expected.
https://github.com/python/typing/issues/182

Strict map with custom reading method or type with custom read instance

So, it is not a problem but I would want an opinion what would be a better way. So I need to read data from a outside source (TCP), that comes basically in this format:
key: value
okey: enum
stuff: 0.12240
amazin: 1020
And I need to parse it into a Haskell accessible format, so the two solutions I thought about, were either to, parse that into a strict String to String map, or record syntax type declarations.
Initially I thought to make a type synonym for my String => String map, and make extractor functions like amazin :: NiceSynonym -> Int, and do the necessary treatment and parsing within the method, but that felt like, sketchy at the time? Then I thought an actual type declaration with record syntax, with a custom Read instance. That was a nightmare, because there is a lot of enums and keys with different types and etc. And it felt... disappointing. It simply wraps the arguments and creates reader functions, not much different from the original: amazin :: TypeDeclaration -> Int.
Now I'm kind of regretting not going with reader functions as I initially envisioned. So, anything else I'm forgetting to consider? Any pros and cons of either sides to take note on? Is one objectively better then the other?
P.S.: Some considerations that may make one or the other better:
Once read I won't need to change it at all whatsoever, it's basically a status report
No need to compare, add, etc., again just status report no point
Not really a need for performance, I wont be reading hundreds a second or anything
TL;DR: Given that input example, what's the best way to make into a Haskell-readable format? map, data constructor, dependent map...
Both ways are very valid in their own respects, but since I was making an API to interact with such protocol too, I preferred the record syntax so I could cover all the properties more easily. Also I wasn't really going to do any checking or treatment in the getter functions, and no matter how boring making the reader instance for my type might have seemed, I bet doing all the get functions manually would be worse. Parsing stuff manually is inherently boring, I guess I was just looking for a magical funcional one liner to make all the work for me.

Resources