Mailing List Archive

mypy question
Hi all,

I am not sure why mypy thinks this

gmPG2.py:554: error: Argument "queries" to "run_rw_queries" has incompatible type "List[Dict[str, str]]"; expected
"List[Dict[str, Union[str, List[Any], Dict[str, Any]]]]" [arg-type]
rows, idx = run_rw_queries(link_obj = conn, queries = queries, return_data = True)
^~~~~~~

should be flagged. The intent is for "queries" to be

a list
of dicts
with keys of str
and values of
str OR
list of anything OR
dict with
keys of str
and values of anything

I'd have thunk list[dict[str,str]] matches that ?

This is on Python 3.11.2 with mypy 1.0.1 on Debian.

Karsten
--
GPG 40BE 5B0E C98E 1713 AFA6 5BC0 3BEA AC80 7D4F C89B
--
https://mail.python.org/mailman/listinfo/python-list
Re: mypy question [ In reply to ]
Am Fri, Dec 29, 2023 at 01:15:29PM +0100 schrieb Karsten Hilbert via Python-list:

> I am not sure why mypy thinks this
>
> gmPG2.py:554: error: Argument "queries" to "run_rw_queries" has incompatible type "List[Dict[str, str]]"; expected
> "List[Dict[str, Union[str, List[Any], Dict[str, Any]]]]" [arg-type]
> rows, idx = run_rw_queries(link_obj = conn, queries = queries, return_data = True)
> ^~~~~~~
>
> should be flagged. The intent is for "queries" to be
>
> a list
> of dicts
> with keys of str
> and values of
> str OR
> list of anything OR
> dict with
> keys of str
> and values of anything
>
> I'd have thunk list[dict[str,str]] matches that ?
>
> This is on Python 3.11.2 with mypy 1.0.1 on Debian.

For completeness, this was the mypy call signature:

mypy --pretty --allow-redefinition --no-strict-optional --ignore-missing-imports --follow-imports silent --show-error-codes --warn-unused-ignores gmPG2.py

Karsten
--
GPG 40BE 5B0E C98E 1713 AFA6 5BC0 3BEA AC80 7D4F C89B
--
https://mail.python.org/mailman/listinfo/python-list
Re: mypy question [ In reply to ]
On 12/29/23 05:15, Karsten Hilbert via Python-list wrote:
> Hi all,
>
> I am not sure why mypy thinks this
>
> gmPG2.py:554: error: Argument "queries" to "run_rw_queries" has incompatible type "List[Dict[str, str]]"; expected
> "List[Dict[str, Union[str, List[Any], Dict[str, Any]]]]" [arg-type]
> rows, idx = run_rw_queries(link_obj = conn, queries = queries, return_data = True)
> ^~~~~~~
>
> should be flagged. The intent is for "queries" to be
>
> a list
> of dicts
> with keys of str
> and values of
> str OR
> list of anything OR
> dict with
> keys of str
> and values of anything
>
> I'd have thunk list[dict[str,str]] matches that ?

Dict[str, str] means the key type and value type should both be strings,
but in your retelling above you indicate lots of possible value types...
actually the mypy guess seems to be a pretty good recreation of your
psuedo-code description.
--
https://mail.python.org/mailman/listinfo/python-list
Re: mypy question [ In reply to ]
Am Fri, Dec 29, 2023 at 07:49:17AM -0700 schrieb Mats Wichmann via Python-list:

> >I am not sure why mypy thinks this
> >
> >gmPG2.py:554: error: Argument "queries" to "run_rw_queries" has incompatible type "List[Dict[str, str]]"; expected
> >"List[Dict[str, Union[str, List[Any], Dict[str, Any]]]]" [arg-type]
> > rows, idx = run_rw_queries(link_obj = conn, queries = queries, return_data = True)
> > ^~~~~~~
> >
> >should be flagged. The intent is for "queries" to be
> >
> >a list
> > of dicts
> > with keys of str
> > and values of
> > str OR
> > list of anything OR
> > dict with
> > keys of str
> > and values of anything
> >
> >I'd have thunk list[dict[str,str]] matches that ?
>
> Dict[str, str] means the key type and value type should both be strings,

Indeed, I know that much, list[dict[str, str]] is what is getting
passed in in this particular invocation of run_rw_queries().

For what it's worth here's the signature of that function:

def run_rw_queries (
link_obj:_TLnkObj=None,
queries:list[dict[str, str | list | dict[str, Any]]]=None,
end_tx:bool=False,
return_data:bool=None,
get_col_idx:bool=False,
verbose:bool=False
) -> tuple[list[dbapi.extras.DictRow], dict[str, int] | None]:

Given that I would have thought that passing in
list[dict[str, str]] for "queries" ought to be type safe.
Mypy indicates otherwise which I am not grokking as to why.

> but in your
> retelling above you indicate lots of possible value types... actually the mypy guess
> seems to be a pretty good recreation of your psuedo-code description.

I agree that mypy's grasp of my intent from

queries:list[dict[str, str | list | dict[str, Any]]]=None,

into

"List[Dict[str, Union[str, List[Any], Dict[str, Any]]]]"

seems accurate. I just don't understand why list[dict[str,
str]] should not pass that construct.

Karsten
--
GPG 40BE 5B0E C98E 1713 AFA6 5BC0 3BEA AC80 7D4F C89B
--
https://mail.python.org/mailman/listinfo/python-list
Re: mypy question [ In reply to ]
On 12/29/23 08:02, Karsten Hilbert via Python-list wrote:

>> Dict[str, str] means the key type and value type should both be strings,
>
> Indeed, I know that much, list[dict[str, str]] is what is getting
> passed in in this particular invocation of run_rw_queries().
>
> For what it's worth here's the signature of that function:
>
> def run_rw_queries (
> link_obj:_TLnkObj=None,
> queries:list[dict[str, str | list | dict[str, Any]]]=None,
> end_tx:bool=False,
> return_data:bool=None,
> get_col_idx:bool=False,
> verbose:bool=False
> ) -> tuple[list[dbapi.extras.DictRow], dict[str, int] | None]:
>
> Given that I would have thought that passing in
> list[dict[str, str]] for "queries" ought to be type safe.
> Mypy indicates otherwise which I am not grokking as to why.

ah... didn't grok what you were asking, sorry - ignore my attempt then.
So you are passing something that has been typed more narrowly than the
function parameter. Can you use a TypeGuard here?
--
https://mail.python.org/mailman/listinfo/python-list
Re: mypy question [ In reply to ]
Am Fri, Dec 29, 2023 at 11:04:59AM -0700 schrieb Mats Wichmann via Python-list:

> >For what it's worth here's the signature of that function:
> >
> > def run_rw_queries (
> > link_obj:_TLnkObj=None,
> > queries:list[dict[str, str | list | dict[str, Any]]]=None,
> > end_tx:bool=False,
> > return_data:bool=None,
> > get_col_idx:bool=False,
> > verbose:bool=False
> > ) -> tuple[list[dbapi.extras.DictRow], dict[str, int] | None]:
> >
> >Given that I would have thought that passing in
> >list[dict[str, str]] for "queries" ought to be type safe.
> >Mypy indicates otherwise which I am not grokking as to why.
>
> ah... didn't grok what you were asking, sorry - ignore my attempt then.

Never mind, the attempt to help is appreciated.

> So you are passing something that has been typed more
> narrowly than the function parameter.

That would then sort of skirt on violation of the Liskov
principle, of which I learned while trying to research this
mypy behaviour.

However, I would not think the above to be a narrowing-down
as it just *selects* one of the explicitely "legal" options.

list[dict[str, str | list | dict[str, Any]]]

should AFAICT expand to:

list[dict[str, dict[str, Any]]]

OR

list[dict[str, list]]

OR

list[dict[str, str]]

the last of which should provide coverage of

[{'some key': 'some value'}]

> Can you use a TypeGuard here?

Not from what I understand about them...

Karsten
--
GPG 40BE 5B0E C98E 1713 AFA6 5BC0 3BEA AC80 7D4F C89B
--
https://mail.python.org/mailman/listinfo/python-list
Re: mypy question [ In reply to ]
On 30/12/23 4:02 am, Karsten Hilbert wrote:

> def run_rw_queries (
> link_obj:_TLnkObj=None,
> queries:list[dict[str, str | list | dict[str, Any]]]=None,

> Given that I would have thought that passing in
> list[dict[str, str]] for "queries" ought to be type safe.

dict[str, str] is not a subtype of dict[str, str | something_else]
because you can assign a value of type something_else to the latter
but not the former.

In this case it happens to be okay because the function is (presumably)
treating the dict passed in as immutable, but MyPy has no way to be sure
of that.

You could try declaring it as a collections.Mapping, which is immutable.

--
Greg
--
https://mail.python.org/mailman/listinfo/python-list
Aw: Re: mypy question [ In reply to ]
Hi Greg,

> dict[str, str] is not a subtype of dict[str, str | something_else]
> because you can assign a value of type something_else to the latter
> but not the former.

I understand what you are saying but I do not yet understand why this
applies to my situation.

I don't have Python at hand currently, so I'll write untested pseudocode:

def print_greeting(greeting:int|str):
print(greeting)

print_greeting('hello')

The above snippet should be equivalent to my more complicated code over
which mypy complains to the equivalent of

"input" is of type "str"
but expected type "Union[str,int]

I do understand that "str" is formally more narrow than "Union [str,int]" and
the type system has every right to not consider them equivalent.

However, this seems like a very common use case: "allow passing in either str or int
and have type checking pass either input as valid" -- yet mypy doesn't seem
to share that idea.

Or else there's something I haven't wrapped my head around yet. But what ?

Karsten

--
https://mail.python.org/mailman/listinfo/python-list
Re: mypy question [ In reply to ]
On 12/29/2023 10:02 AM, Karsten Hilbert via Python-list wrote:
> Am Fri, Dec 29, 2023 at 07:49:17AM -0700 schrieb Mats Wichmann via Python-list:
>
>>> I am not sure why mypy thinks this
>>>
>>> gmPG2.py:554: error: Argument "queries" to "run_rw_queries" has incompatible type "List[Dict[str, str]]"; expected
>>> "List[Dict[str, Union[str, List[Any], Dict[str, Any]]]]" [arg-type]
>>> rows, idx = run_rw_queries(link_obj = conn, queries = queries, return_data = True)
>>> ^~~~~~~
>>>
>>> should be flagged. The intent is for "queries" to be
>>>
>>> a list
>>> of dicts
>>> with keys of str
>>> and values of
>>> str OR
>>> list of anything OR
>>> dict with
>>> keys of str
>>> and values of anything
>>>
>>> I'd have thunk list[dict[str,str]] matches that ?
>>
>> Dict[str, str] means the key type and value type should both be strings,
>
> Indeed, I know that much, list[dict[str, str]] is what is getting
> passed in in this particular invocation of run_rw_queries().
>
> For what it's worth here's the signature of that function:
>
> def run_rw_queries (
> link_obj:_TLnkObj=None,
> queries:list[dict[str, str | list | dict[str, Any]]]=None,
> end_tx:bool=False,
> return_data:bool=None,
> get_col_idx:bool=False,
> verbose:bool=False
> ) -> tuple[list[dbapi.extras.DictRow], dict[str, int] | None]:
>
> Given that I would have thought that passing in
> list[dict[str, str]] for "queries" ought to be type safe.
> Mypy indicates otherwise which I am not grokking as to why.
>
>> but in your
>> retelling above you indicate lots of possible value types... actually the mypy guess
>> seems to be a pretty good recreation of your psuedo-code description.
>
> I agree that mypy's grasp of my intent from
>
> queries:list[dict[str, str | list | dict[str, Any]]]=None,
>
> into
>
> "List[Dict[str, Union[str, List[Any], Dict[str, Any]]]]"
>
> seems accurate. I just don't understand why list[dict[str,
> str]] should not pass that construct.

Maybe better to ask the mypy people directly.

> Karsten
> --
> GPG 40BE 5B0E C98E 1713 AFA6 5BC0 3BEA AC80 7D4F C89B

--
https://mail.python.org/mailman/listinfo/python-list
Re: mypy question [ In reply to ]
On 12/29/2023 10:02 AM, Karsten Hilbert via Python-list wrote:
> I agree that mypy's grasp of my intent from
>
> queries:list[dict[str, str | list | dict[str, Any]]]=None,
>
> into
>
> "List[Dict[str, Union[str, List[Any], Dict[str, Any]]]]"
>
> seems accurate. I just don't understand why list[dict[str,
> str]] should not pass that construct.

I made a tiny test program with your type signature, and got this error
message from mypy:

c:\temp\python\typing_test.py:3: error: X | Y syntax for unions requires
Python 3.10 [syntax]

Aside from that, this variation causes no mypy error (you must use
Sequence instead of List), and is also more clear about what you are
trying to get:

from typing import Union, Sequence, Dict

DictType1 = Dict[str, str]
DictType2 = Dict[str, Sequence]
DictType3 = Dict[str, Dict]
QueryType = Sequence[Union[DictType1, DictType2, DictType3]]

def test_typing(queries:QueryType=None):
print(type(queries))

d1 = {'k1': 'v1', 'k2': 'v2'}
queries = [d1,]
test_typing(queries)

I'm not sure if this captures exactly what you want, but it avoids the
problem where mypy does not regard str and Union[str, list] as
equivalent types. I tested this using Python 3.12.



--
https://mail.python.org/mailman/listinfo/python-list
Aw: Re: mypy question [ In reply to ]
Dear Thomas,

thanks for taking the time to look into my issue.

Maybe it helps if I explain what I want (sorry that my web mailer does not respect
indentation, I will insert dots).

I want a function to run SQL queries:

run_queries(conn, queries):
...for q in queries:
......conn.execute(q)

I now want to add type hints such that my large codebase can
be checked for silly doings. First, queries is to be a list
of the SQL to run:

run_queries(conn, queries:list):

Then, each list entry can be

...a string holding simple, complete SQL (say "SELECT 1")

run_queries(conn, queries:list[str]):

or

...a dict holding the SQL and arguments for parameters

run_queries(conn, queries:list[dict]):

So, taken together:

run_queries(conn, queries:list[str|dict]):

(yes, this is in Python 3.11/3.12)

Now, when it is a list of dicts I want to further constrain the
dicts. Each is to contain the keys "SQL" and "args". So the keys
are of type str. The values for the keys will be of various types,
such that I chose Any as pseudo-type, so that each list entry that
is of type dict should be dict[str, Any], hence:

queries = [{'SQL': 'SELECT %(value)s', 'args': {'value': 1}}]

and

run_queries(conn, queries:list[str|dict[str, Any]]):

If I now call this function with a simple SQL query:

SQL_query = 'SELECT 1' # should be type str ?
queries = [SQL_query] # should be type list[str] ?
run_queries(conn, queries = queries)

and run mypy over that (at least inside my complex codebase) I will
get a type mismatch being hinted at.

So far I don't grasp at which point my reasoning above is faulty.

Karsten
--
https://mail.python.org/mailman/listinfo/python-list
Re: Aw: Re: mypy question [ In reply to ]
On 12/30/2023 10:08 AM, Karsten Hilbert via Python-list wrote:
> Dear Thomas,
>
> thanks for taking the time to look into my issue.
>
> Maybe it helps if I explain what I want (sorry that my web mailer does not respect
> indentation, I will insert dots).
>
> I want a function to run SQL queries:
>
> run_queries(conn, queries):
> ...for q in queries:
> ......conn.execute(q)
>
> I now want to add type hints such that my large codebase can
> be checked for silly doings. First, queries is to be a list
> of the SQL to run:
>
> run_queries(conn, queries:list):
>
> Then, each list entry can be
>
> ...a string holding simple, complete SQL (say "SELECT 1")
>
> run_queries(conn, queries:list[str]):
>
> or
>
> ...a dict holding the SQL and arguments for parameters
>
> run_queries(conn, queries:list[dict]):
>
> So, taken together:
>
> run_queries(conn, queries:list[str|dict]):
>
> (yes, this is in Python 3.11/3.12)
>
> Now, when it is a list of dicts I want to further constrain the
> dicts. Each is to contain the keys "SQL" and "args". So the keys
> are of type str. The values for the keys will be of various types,
> such that I chose Any as pseudo-type, so that each list entry that
> is of type dict should be dict[str, Any], hence:
>
> queries = [{'SQL': 'SELECT %(value)s', 'args': {'value': 1}}]
>
> and
>
> run_queries(conn, queries:list[str|dict[str, Any]]):
>
> If I now call this function with a simple SQL query:
>
> SQL_query = 'SELECT 1' # should be type str ?
> queries = [SQL_query] # should be type list[str] ?
> run_queries(conn, queries = queries)
>
> and run mypy over that (at least inside my complex codebase) I will
> get a type mismatch being hinted at.
>
> So far I don't grasp at which point my reasoning above is faulty.
>
> Karsten

I am not very expert in Python type hints. In working up the example
program I just posted, I got an error message from mypy that remarked
that "list" is invariant, and to try Sequence which is "covariant". I
don't know what that means (and I haven't looked into it yet), but when
I changed from list to Sequence as suggested, mypy stopped complaining.

Here is the exact error message, and it has a reference you might want
to follow up with:

c:\temp\python\typing_test.py:16: note: "List" is invariant -- see
https://mypy.readthedocs.io/en/stable/common_issues.html#variance
c:\temp\python\typing_test.py:16: note: Consider using "Sequence"
instead, which is covariant

Before that, mypy insisted that str and Union[str, list] were
incompatible argument types, which is something you are seeing, too.

I suggest that you build up your types as in my example, so that it's
very clear what they are and very easy to change them, and use Sequence
instead of List (or list). See if that will do the job.

--
https://mail.python.org/mailman/listinfo/python-list
Re: Aw: Re: mypy question [ In reply to ]
On 12/30/2023 10:08 AM, Karsten Hilbert via Python-list wrote:
> Dear Thomas,
>
> thanks for taking the time to look into my issue.
>
> Maybe it helps if I explain what I want (sorry that my web mailer does not respect
> indentation, I will insert dots).
>
> I want a function to run SQL queries:
>
> run_queries(conn, queries):
> ...for q in queries:
> ......conn.execute(q)
>
> I now want to add type hints such that my large codebase can
> be checked for silly doings. First, queries is to be a list
> of the SQL to run:
>
> run_queries(conn, queries:list):
>
> Then, each list entry can be
>
> ...a string holding simple, complete SQL (say "SELECT 1")
>
> run_queries(conn, queries:list[str]):

It occurs to me that you could simplify things if you converted those
plain query strings to dicts:

'SELECT 1' --> {'SQL': 'SELECT 1'}

I'm fairly sure your database queries don't actually give you strings or
dicts, right? You probably get lists (or iterators) of tuples and
somewhere you convert them to the arguments you are feeding to
run_queries(). At least, that is how the standard Python db adapters
work. If you change that conversion step, your arguments to
run_queries() will all be lists of dicts, making your code simpler and
reducing the complexity of the type hints.

> or
>
> ...a dict holding the SQL and arguments for parameters
>
> run_queries(conn, queries:list[dict]):
>
> So, taken together:
>
> run_queries(conn, queries:list[str|dict]):
>
> (yes, this is in Python 3.11/3.12)
>
> Now, when it is a list of dicts I want to further constrain the
> dicts. Each is to contain the keys "SQL" and "args". So the keys
> are of type str. The values for the keys will be of various types,
> such that I chose Any as pseudo-type, so that each list entry that
> is of type dict should be dict[str, Any], hence:
>
> queries = [{'SQL': 'SELECT %(value)s', 'args': {'value': 1}}]
>
> and
>
> run_queries(conn, queries:list[str|dict[str, Any]]):
>
> If I now call this function with a simple SQL query:
>
> SQL_query = 'SELECT 1' # should be type str ?
> queries = [SQL_query] # should be type list[str] ?
> run_queries(conn, queries = queries)
>
> and run mypy over that (at least inside my complex codebase) I will
> get a type mismatch being hinted at.
>
> So far I don't grasp at which point my reasoning above is faulty.
>
> Karsten

--
https://mail.python.org/mailman/listinfo/python-list
Aw: Re: Re: mypy question [ In reply to ]
> It occurs to me that you could simplify things if you converted those
> plain query strings to dicts:
>
> 'SELECT 1' --> {'SQL': 'SELECT 1'}

Ha, indeed. There's likely not that many "simple string SQL queries"
in that codebase so I shall take it as an opportunity to refactor them.

So, at least that much good has come from the mypy hint ;-)

Karsten
--
https://mail.python.org/mailman/listinfo/python-list
Aw: Re: Re: mypy question [ In reply to ]
> I'm fairly sure your database queries don't actually give you strings or
> dicts, right? You probably get lists (or iterators) of tuples and
> somewhere you convert them to the arguments you are feeding to
> run_queries().

Ah, no, those queries are enshrined within the middleware as Python strings
with placeholdders. When in need of being run they are assembled into
a list of dicts-enriched-with-arguments-per-query (and fed to run_queries()).

As to what queries *give* me: I have set up psycopg2 to, indeed, hand
me a list of dicts (DictRow instances, that is). Those are then used
in display rather than being fed to run_queries().

Karsten
--
https://mail.python.org/mailman/listinfo/python-list
Re: mypy question [ In reply to ]
> On 30 Dec 2023, at 15:11, Karsten Hilbert via Python-list <python-list@python.org> wrote:
>
> queries = [{'SQL': 'SELECT %(value)s', 'args': {'value': 1}}]
>
> and
>
> run_queries(conn, queries:list[str|dict[str, Any]]):

In cases like this I often use a wrapper class in place of a simple str.
If you have a class SqlString then your type becomes list[SqlString].

You may find that SqlString gains interesting methods over time.

Barry
--
https://mail.python.org/mailman/listinfo/python-list
Re: Aw: Re: mypy question [ In reply to ]
On Sun, 31 Dec 2023 at 03:38, Thomas Passin via Python-list
<python-list@python.org> wrote:
> I am not very expert in Python type hints. In working up the example
> program I just posted, I got an error message from mypy that remarked
> that "list" is invariant, and to try Sequence which is "covariant". I
> don't know what that means (and I haven't looked into it yet), but when
> I changed from list to Sequence as suggested, mypy stopped complaining.
>

Ah, I think you've hit on the problem there. Consider this:

def add_item(stuff: dict[str: str | int]):
stuff["spam"] = "ham"
stuff["vooom"] = 1_000_000

Is it valid to pass this function a dict[str: str]? No, because it's
going to add an integer into it.

Hopefully that helps explain what's going on a bit.

ChrisA
--
https://mail.python.org/mailman/listinfo/python-list
Re: mypy question [ In reply to ]
On 12/30/2023 9:14 AM, Thomas Passin via Python-list wrote:
> On 12/29/2023 10:02 AM, Karsten Hilbert via Python-list wrote:
>> I agree that mypy's grasp of my intent from
>>
>>     queries:list[dict[str, str | list | dict[str, Any]]]=None,
>>
>> into
>>
>>     "List[Dict[str, Union[str, List[Any], Dict[str, Any]]]]"
>>
>> seems accurate. I just don't understand why list[dict[str,
>> str]] should not pass that construct.
>
> I made a tiny test program with your type signature, and got this error
> message from mypy:
>
> c:\temp\python\typing_test.py:3: error: X | Y syntax for unions requires
> Python 3.10  [syntax]
>
> Aside from that, this variation causes no mypy error (you must use
> Sequence instead of List), and is also more clear about what you are
> trying to get:
>
> from typing import Union, Sequence, Dict
>
> DictType1 = Dict[str, str]
> DictType2 = Dict[str, Sequence]
> DictType3 = Dict[str, Dict]
> QueryType = Sequence[Union[DictType1, DictType2, DictType3]]
>
> def test_typing(queries:QueryType=None):
>     print(type(queries))
>
> d1 = {'k1': 'v1', 'k2': 'v2'}
> queries = [d1,]
> test_typing(queries)
>
> I'm not sure if this captures exactly what you want, but it avoids the
> problem where mypy does not regard str and Union[str, list] as
> equivalent types.  I tested this using Python 3.12.

In doing more testing, I have learned that my suggestion above does
work, *except* that you cannot mix-and-match different DictTypex types
within the same Sequence - meaning within the same query argument. Any
of the Union types is OK but they all have to be the same in any instance.

--
https://mail.python.org/mailman/listinfo/python-list
Re: Aw: Re: mypy question [ In reply to ]
On 31/12/23 8:05 am, Chris Angelico wrote:
> Ah, I think you've hit on the problem there. Consider this:
>
> def add_item(stuff: dict[str: str | int]):
> stuff["spam"] = "ham"
> stuff["vooom"] = 1_000_000

Yep, that's it exactly. It's not the union itself that's the problem,
but the fact that there's a *mutable container* containing that type.

--
Greg
--
https://mail.python.org/mailman/listinfo/python-list
Re: mypy question [ In reply to ]
On 31/12/23 10:06 am, Thomas Passin wrote:
> my suggestion above does
> work, *except* that you cannot mix-and-match different DictTypex types

Have you tried declaring the argument as a Mapping instead of a dict?
Seeing as Thomas Passin's Sequence experiment worked, it seems like this
should work too.

--
Greg
--
https://mail.python.org/mailman/listinfo/python-list
Re: mypy question [ In reply to ]
Thanks to all. I ended up using Sequence for the list part
and Mapping for the dict part, which does require "import
typing" which I would rather have avoided.

Karsten
--
GPG 40BE 5B0E C98E 1713 AFA6 5BC0 3BEA AC80 7D4F C89B
--
https://mail.python.org/mailman/listinfo/python-list
Re: mypy question [ In reply to ]
Op 29/12/2023 om 16:02 schreef Karsten Hilbert via Python-list:

> Am Fri, Dec 29, 2023 at 07:49:17AM -0700 schrieb Mats Wichmann via Python-list:
>
>>> I am not sure why mypy thinks this
>>>
>>> gmPG2.py:554: error: Argument "queries" to "run_rw_queries" has incompatible type "List[Dict[str, str]]"; expected
>>> "List[Dict[str, Union[str, List[Any], Dict[str, Any]]]]" [arg-type]
>>> rows, idx = run_rw_queries(link_obj = conn, queries = queries, return_data = True)
>>> ^~~~~~~
>>>
>>> should be flagged. The intent is for "queries" to be
>>>
>>> a list
>>> of dicts
>>> with keys of str
>>> and values of
>>> str OR
>>> list of anything OR
>>> dict with
>>> keys of str
>>> and values of anything
>>>
>>> I'd have thunk list[dict[str,str]] matches that ?
>> Dict[str, str] means the key type and value type should both be strings,
> Indeed, I know that much, list[dict[str, str]] is what is getting
> passed in in this particular invocation of run_rw_queries().
>
> For what it's worth here's the signature of that function:
>
> def run_rw_queries (
> link_obj:_TLnkObj=None,
> queries:list[dict[str, str | list | dict[str, Any]]]=None,
> end_tx:bool=False,
> return_data:bool=None,
> get_col_idx:bool=False,
> verbose:bool=False
> ) -> tuple[list[dbapi.extras.DictRow], dict[str, int] | None]:
>
> Given that I would have thought that passing in
> list[dict[str, str]] for "queries" ought to be type safe.
> Mypy indicates otherwise which I am not grokking as to why.
>
>> but in your
>> retelling above you indicate lots of possible value types... actually the mypy guess
>> seems to be a pretty good recreation of your psuedo-code description.
> I agree that mypy's grasp of my intent from
>
> queries:list[dict[str, str | list | dict[str, Any]]]=None,
>
> into
>
> "List[Dict[str, Union[str, List[Any], Dict[str, Any]]]]"
>
> seems accurate. I just don't understand why list[dict[str,
> str]] should not pass that construct.

Sorry for the late reaction and may be I am missing something, but I was wondering if
your type hint for queries shouldn't be the following.

queries:list[dict[str,str]|dict[str,list]|dict[str,dict[str, dict[str, Ant]]]

My impression at this moment is that you are write something like: dict[str, str | int] as
as shorthand for dict[str, str] | dict[str, int]. But those two are different types.

--
Antoon Pardon.
--
https://mail.python.org/mailman/listinfo/python-list
Re: mypy question [ In reply to ]
Am Fri, Jan 12, 2024 at 02:23:43PM +0100 schrieb Antoon Pardon via Python-list:

> > queries:list[dict[str, str | list | dict[str, Any]]]=None,
> >
> >into
> >
> > "List[Dict[str, Union[str, List[Any], Dict[str, Any]]]]"
> >
> >seems accurate. I just don't understand why list[dict[str,
> >str]] should not pass that construct.
>
> Sorry for the late reaction

ne'er mind ya

> I was wondering if
> your type hint for queries shouldn't be the following.
>
> queries:list[dict[str,str]|dict[str,list]|dict[str,dict[str, dict[str, Ant]]]
>
> My impression at this moment is that you are write something like: dict[str, str | int] as
> as shorthand for dict[str, str] | dict[str, int].

I do.

> But those two are different types.

A-ha ! In what way ?

Karsten
--
GPG 40BE 5B0E C98E 1713 AFA6 5BC0 3BEA AC80 7D4F C89B
--
https://mail.python.org/mailman/listinfo/python-list
Re: mypy question [ In reply to ]
Am Sat, Jan 13, 2024 at 09:20:00PM +0100 schrieb Karsten Hilbert via Python-list:

> > I was wondering if
> > your type hint for queries shouldn't be the following.
> >
> > queries:list[dict[str,str]|dict[str,list]|dict[str,dict[str, dict[str, Ant]]]

Wait, not really. Let me give an example. Here's three times
the same query (as far as PostgreSQL is concerned, after
having been passed through psycopg2):

queries = [.
{
'SQL': 'SELECT 1'
},
{
'SQL': 'SELECT %s',
'args': [1]
},
{
'SQL': 'SELECT %(value)s',
'args': {'value': 1}
}
]

The value for key "SQL" will always be str-like.

The value for "args" can be a list or a dict itself.

If "args" is a dict it will be of type [str, Any].

That's what I am trying to tell mypy.

Karsten
--
GPG 40BE 5B0E C98E 1713 AFA6 5BC0 3BEA AC80 7D4F C89B
--
https://mail.python.org/mailman/listinfo/python-list