I would like PyCharm to warn me on the following python3 code:
def foo() -> str:
return 'abc'
x: int = foo() # I want to be warned here
Is there an option I can enable to get this warning?
The motivation here is that I have functions whose return-types are not as easily deducible at first glance like in this example. I want to declare what I think the types of my variables should be, for readability, and I want PyCharm to deduce whether what I think is correct.
Turns out this is an open issue in PyCharm (PY-24832).
Related
PyCharm Version: 2019.1.2
Python Version: 3.7
I am trying to use least code to reproduce the problem. And this is the snippet of my code:
def sql_reader():
def outer(func):
def wrapped_function(*args, **kwargs):
func(*args, **kwargs)
return [{"a": 1, "b": 2}]
return wrapped_function
return outer
#sql_reader()
def function_read():
return "1"
result = function_read()
for x in result:
print(x['a'])
print(result)
Basically, what I am doing is to "decorate" some function to output different types. For example, in this snippet, the function being decorated is returning 1 which is int. However, in decorator, I change the behavior and return list of dict.
Functionally speaking, it works fine. But it looks like my IDE always complains about it which is annoying as below:
Is there anyway I can get rid of this warning message?
With all due respect, you are using an over 3 year old version of PyCharm. I struggle to see a reason for this. The community edition is free and requires no root privileges to unpack and run on Linux systems. You should seriously consider upgrading to the latest version.
Same goes for Python by the way. You can install any version (including the latest) via Pyenv without root privileges. Although the Python version requirement may be subject to external restrictions for the code you are working on, so that is just a suggestion. But for the IDE I see no reason to use such an outdated version.
Since I am not using your PyCharm version, I can not reproduce your problem. Version 2022.2.3 has no such issues with your code. Be that as it may, there are a few things you can do to make life easier for static type checkers (and by extension for yourself).
The first thing I would always suggest is to use functools.wraps, when you are wrapping functions via a decorator. This preserves a lot of useful metadata about the wrapped function and even stores a reference to it in the wrapper's __wrapped__ attribute.
The second is proper type annotations. This should go for any code you write, unless it really is just a quick-and-dirty draft script that you will only use once and then throw away. The benefits of proper annotations especially in conjunction with modern IDEs are huge. There are many resources out there explaining them, so I won't go into details here.
In this concrete case, proper type hints will remove ambiguity about the return types of your functions and should work with any IDE (bugs non withstanding). In my version of PyCharm the return type of your wrapper function is inferred to be Any because no annotations are present, which prevents any warning like yours to pop up, but also doesn't allow any useful auto-suggestions to be provided.
Here is what I would do with your code: (should be compatible with Python 3.7)
from functools import wraps
from typing import Any, Callable, Dict, List
AnyFuncT = Callable[..., Any]
ResultsT = List[Dict[str, int]]
def sql_reader() -> Callable[[AnyFuncT], Callable[..., ResultsT]]:
def outer(func: AnyFuncT) -> Callable[..., ResultsT]:
#wraps(func)
def wrapper(*args: Any, **kwargs: Any) -> ResultsT:
func(*args, **kwargs)
return [{"a": 1, "b": 2}]
return wrapper
return outer
#sql_reader()
def function_read() -> str:
return "1"
Adding reveal_type(function_read()) underneath and calling mypy on this file results in the following:
note: Revealed type is "builtins.list[builtins.dict[builtins.str, builtins.int]]"
Success: no issues found in 1 source file
As you can see, at least mypy now correctly infers the type returned by the wrapper function we put around function_read. Your IDE should also correctly infer the types involved, but as I said I cannot verify this with my version.
Moreover, now PyCharm will give you auto-suggestions for methods available on the types involved:
results = function_read()
first = results[0]
value = first["a"]
If I now start typing results., PyCharm will suggest things like append, extend etc. because it recognizes result as a list. If I type first., it will suggest keys, values etc. (inferring it as a dictionary) and if I type value. it will give options like imag, real and to_bytes, which are available for integers.
More information: typing module docs
I actually don't have any question about my code but i use a ide named pycharm while running my code i don't get any error but my ide gives me a warning why is that so?
Here's my code :
def hi():
global d
d = 5
hi()
print(d)
My code works fine but my ide gives me a warning at line 2 of my code which is Global variable 'd' is undefined at the module level.
Did i do anything wrong in my code i just created a global variable through a function and accesed it outside the function.
does anyone know why this is happening?
As you said there is no error, just a warning. You can look up the different inspection severity levels here
I quote from this website:
Warning: marks code fragments that might produce bugs or require enhancement.
So Pycharm is trying to tell you that using global in this way could lead to bugs down the line, especially if your code gets more complicated. This warning appears so that you get a change to rethink how your code works and that there are maybe better ways to achieve the same goal.
In this case the warning comes from the fact that d is undefined at the module level, which can be fixed by defining it, e.g. at the top.
d = 11
In general there are many reason why one should avoid the global keyword (see discussion here), but if you know why you are using it then its fine.
Global variables are never recommended as they could produce errors in the future as see Why are global variables evil?
your code should be
def hi():
return 5
print(hi())
If you just want to get rid of the warning "Global variable 'd' is undefined at the module level."
You could declare the desired global variable and don't not assign a value (None) with type hints.
d :str
d :str
def hi():
global d
d = 5
hi()
print(d)
I was looking at typings set up on the web but I was curious if I can have multiple types. Example:
self.test: str or None = None
It shows valid on my intellisense but I wasnt sure if it computed it different.
I was trying to implement something equivalent to typescript.
test: number|null = null;
But I didn't see specific types in this regard. Pretty much all my items have the option of being None/Null.
You should use Union https://docs.python.org/3/library/typing.html#typing.Union
from typing import Union
self.test: Union[str, None]
You can use Optional[X] as a shorthand for Union[X, None].
I ran into an issue when using mypy and have been able to find any help/reports regarding it. The following simplified code and error message should be self-explanatory:
#!/usr/bin/env python3
from typing import List, Union
class Corpus:
path: List[str]
def __init__(self, path:Union[str,List[str]]) -> None:
if type(path) == str:
self.path = [path]
else:
self.path = path
Mypy gives the following errors:
simplified.py:10: error: List item 0 has incompatible type "Union[str, List[str]]"; expected "str"
simplified.py:12: error: Incompatible types in assignment (expression has type "Union[str, List[str]]", variable has type "List[str]")
Even though the type of path variable is checked so that self.path should always result in string list, mypy complains about incompatible types.
Am I overlooking something or is this a bug in mypy?
(It it is a bug, should I go with #type: ignore annotation or is there a better work-around?)
(Some background: I decided to ease my life by writing a module which would take care of some repeating work. The argument in question should be a path to text data and I expect it to be only one string most of the time so I don't want to force putting it in a list. However, I wish to allow specifying more paths too. Internally, I store it as a list anyway as iterator over the class is always initialized with such list (and then possibly extends it further by "unpacking" directories)).
Try using isinstance(path, str) instead of type(path) == str. The former makes mypy typecheck your code without reporting an error.
Mypy really ought to support the latter form though -- there's an open feature request about it. The reason why this isn't implemented yet is almost certainly due to lack of time -- mypy's core team is pretty small, and there's an easy workaround in this case, so the feature was deprioritized.
(But hey, mypy is open source, so if you have some spare time...)
I'm having trouble with the input() function in Python3.4 using the Anaconda integrated editor. If I just type
x = input()
into the editor, it returns a blank line that I can type text into. If I type:
foo
into this line, I would expect 'foo' be stored as a string with variable name x. But, instead I get:
NameError: name 'foo' is not defined
To make the function work as expected, I must instead type in:
'foo'
which is unfortunate because what I really want is just to pause my code and wait for an arbitrary user input, and I read somewhere that "wait = input()" is the most pythonic way to do this. Using that line in my actual script returns an "unexpected EOF" error - I assume as another symptom of the same problem. Can anyone suggest a workaround?
Note: I suspect this is an Anaconda-specific problem, given the following reference:
https://docs.python.org/3.4/library/functions.html#input
Thanks for your time.
Your code is being run by Python 2, not 3. I don't know enough about Anaconda to know if the problem is with their editor, or if you have your path messed up, but the problem is that the wrong version of Python is being used.