Why does "import pyautogui" give an error [duplicate] - python

This question already has an answer here:
Why is pyauto gui and Pycharm not working for me?
(1 answer)
Closed last year.
I dont understand why this gives back an error and i'm really confused.
>>> import pyautogui
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/Users/connorgooch/Library/Python/2.7/lib/python/site-packages/pyautogui/__init__.py", line 249, in <module>
import mouseinfo
File "/Library/Python/2.7/site-packages/mouseinfo/__init__.py", line 100, in <module>
from rubicon.objc import ObjCClass, CGPoint
File "/Library/Python/2.7/site-packages/rubicon/objc/__init__.py", line 3, in <module>
from .runtime import ( # noqa: F401
File "/Library/Python/2.7/site-packages/rubicon/objc/runtime.py", line 785
self.restype, *self.argtypes = ctypes_for_method_encoding(self.encoding)
^
SyntaxError: invalid syntax
How do I fix this?

Diagnosis
You're running the library in a version of Python that's too old.
You can tell because assignment of the form ..., *whatever = some_function() became valid only in a relatively recent version of Python.
Prior to that, having a unary * (splat operator) like that on the left side of an assignment was a syntax error.
More specifically, you're using Python 2, which we can tell by both the fact that this feature became available in Python 3.0, and the fact that the traceback has paths like this: /Library/Python/2.7/... (that 2.7 is the Python version).
Solution
Use a newer version of Python.
I can't tell you how to do that because that totally depends on how you're currently running Python.
On some systems, the python command is still Python 2, and you need to call python3 to get Python 3. You might also have a situation where you have separate commands like python27 for Python 2.7, python38 for Python 3.8, and python39 for Python 3.9, but python3 and python point to Python 3.8 instead of either the latest 2 or the latest 3.
Also, on some systems, each Python version is installed in a different directory, and if you specify the right path you don't need to worry about the exact command name.
So if you're calling Python from a shell, you may need to change the PATH or the command or both. If you're calling Python from an IDE, there might be a setting for it. And so on.
Similarly, you might need to actually install a newer version of Python, but the right way to do that depends on your system.
Maybe the package manager provided by your operating system like apt or yum or any number of others, or a third-party package manager like brew or chocolatey, or maybe you're using a tool that manages multiple Python versions. Or maybe you just download it manually from the Python webpage.
Based on your traceback, the fact that some of the paths start with /Library/... suggests that you're on MacOS, which means you can probably just get Python 3 by using the command python3, or changing the path your tool is using to Library/Python/3.? (replace ? with the right minor version). And if you don't already have it installed, you can get it from the Python website or the "homebrew" package manager if you're using that or whatever else works on Mac.
Solution (if you really can't use a newer Python)
You can change the line that's raising the syntax error.
There are many equivalent ways to do this once you understand what's going on.
Here is one pattern which is less readable than most, but which you can use in all cases with no understanding or review or changes:
self.restype, self.argtypes = (lambda r: (r[0], list(r[1:])))(ctypes_for_method_encoding(self.encoding))
Background
In Python, a function can return a tuple or something similar like a list.
This is how returning multiple values is implemented.
In order to make this work on the assignment side, Python can do something called "iterable unpacking": foo, bar = my_function() (this is more generally known by other names too, such as "de-structuring assignment").
(This is also what's happening when you "swap" values: foo, bar = bar, foo is actually semantically equivalent to temp = (bar, foo); foo = temp[0]; bar = temp[1]; del temp. First a tuple is created, and then it goes through de-structuring assignment.)
In Python 3, they added a feature where an assignment with the "splat" operator (*) on one of the values will capture "the rest" of the de-structured values. So if you do temp = (1, 2, 3, 4, 5), then foo, bar, *qux = temp will result in foo = 1, bar = 2, and qux = (3, 4, 5).
But in earlier versions of Python that feature didn't exist.
So the line
self.restype, *self.argtypes = ctypes_for_method_encoding(self.encoding)
is taking the return value from ctypes_for_method_encoding, and assigning the first element of it into self.restype and a tuple holding the rest of the elements from it into self.argtypes.

First try:-
python -m pip install --upgrade pyautogui
If it does not work, then in File "/Library/Python/2.7/site-packages/rubicon/objc/runtime.py", line 785
self.restype, *self.argtypes = ctypes_for_method_encoding(self.encoding)
Try correcting the syntax because you have a syntax error in this line. You can find the syntax on google.
I think you have an error in the asterisk symbol *. But I am not sure.

Related

I'm trying to use imapgrab to imap gmail, but I can't because of the following error. imapgrab error DEBUG_000 [duplicate]

When I try to use a print statement in Python, it gives me this error:
>>> print "Hello, World!"
File "<stdin>", line 1
print "Hello, World!"
^
SyntaxError: Missing parentheses in call to 'print'
What does that mean?
This error message means that you are attempting to use Python 3 to follow an example or run a program that uses the Python 2 print statement:
print "Hello, World!"
The statement above does not work in Python 3. In Python 3 you need to add parentheses around the value to be printed:
print("Hello, World!")
“SyntaxError: Missing parentheses in call to 'print'” is a new error message that was added in Python 3.4.2 primarily to help users that are trying to follow a Python 2 tutorial while running Python 3.
In Python 3, printing values changed from being a distinct statement to being an ordinary function call, so it now needs parentheses:
>>> print("Hello, World!")
Hello, World!
In earlier versions of Python 3, the interpreter just reports a generic syntax error, without providing any useful hints as to what might be going wrong:
>>> print "Hello, World!"
File "<stdin>", line 1
print "Hello, World!"
^
SyntaxError: invalid syntax
As for why print became an ordinary function in Python 3, that didn't relate to the basic form of the statement, but rather to how you did more complicated things like printing multiple items to stderr with a trailing space rather than ending the line.
In Python 2:
>>> import sys
>>> print >> sys.stderr, 1, 2, 3,; print >> sys.stderr, 4, 5, 6
1 2 3 4 5 6
In Python 3:
>>> import sys
>>> print(1, 2, 3, file=sys.stderr, end=" "); print(4, 5, 6, file=sys.stderr)
1 2 3 4 5 6
Starting with the Python 3.6.3 release in September 2017, some error messages related to the Python 2.x print syntax have been updated to recommend their Python 3.x counterparts:
>>> print "Hello!"
File "<stdin>", line 1
print "Hello!"
^
SyntaxError: Missing parentheses in call to 'print'. Did you mean print("Hello!")?
Since the "Missing parentheses in call to print" case is a compile time syntax error and hence has access to the raw source code, it's able to include the full text on the rest of the line in the suggested replacement. However, it doesn't currently try to work out the appropriate quotes to place around that expression (that's not impossible, just sufficiently complicated that it hasn't been done).
The TypeError raised for the right shift operator has also been customised:
>>> print >> sys.stderr
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for >>: 'builtin_function_or_method' and '_io.TextIOWrapper'. Did you mean "print(<message>, file=<output_stream>)"?
Since this error is raised when the code runs, rather than when it is compiled, it doesn't have access to the raw source code, and hence uses meta-variables (<message> and <output_stream>) in the suggested replacement expression instead of whatever the user actually typed. Unlike the syntax error case, it's straightforward to place quotes around the Python expression in the custom right shift error message.
Unfortunately, the old xkcd comic isn't completely up to date anymore.
Since Python 3.0 you have to write:
print("Hello, World!")
And someone has still to write that antigravity library :(
There is a change in syntax from Python 2 to Python 3.
In Python 2,
print "Hello, World!"
will work but in Python 3, use parentheses as
print("Hello, World!")
This is equivalent syntax to Scala and near to Java.
Basically, since Python 3.x you need to use print with parenthesis.
Python 2.x: print "Lord of the Rings"
Python 3.x: print("Lord of the Rings")
Explanation
print was a statement in 2.x, but it's a function in 3.x. Now, there are a number of good reasons for this.
With function format of Python 3.x, more flexibility comes when printing multiple items with comma separated.
You can't use argument splatting with a statement. In 3.x if you have a list of items that you want to print with a separator, you can do this:
>>> items = ['foo', 'bar', 'baz']
>>> print(*items, sep='+')
foo+bar+baz
You can't override a statement. If you want to change the behavior of print, you can do that when it's a function but not when it's a statement.
If your code should work in both Python 2 and 3, you can achieve this by loading this at the beginning of your program:
from __future__ import print_function # If code has to work in Python 2 and 3!
Then you can print in the Python 3 way:
print("python")
If you want to print something without creating a new line - you can do this:
for number in range(0, 10):
print(number, end=', ')
In Python 3, you can only print as:
print("STRING")
But in Python 2, the parentheses are not necessary.
I could also just add that I knew everything about the syntax change between Python2.7 and Python3, and my code was correctly written as print("string") and even
print(f"string")...
But after some time of debugging I realized that my bash script was calling python like:
python file_name.py
which had the effect of calling my python script by default using python2.7 which gave the error. So I changed my bash script to:
python3 file_name.py
which of coarse uses python3 to run the script which fixed the error.
print('Hello, World!')
You're using python 3, where you need brackets when printing.
Outside of the direct answers here, one should note the other key difference between python 2 and 3. The official python wiki goes into almost all of the major differences and focuses on when you should use either of the versions. This blog post also does a fine job of explaining the current python universe and the somehow unsolved puzzle of moving to python 3.
As far as I can tell, you are beginning to learn the python language. You should consider the aforementioned articles before you continue down the python 3 route. Not only will you have to change some of your syntax, you will also need to think about which packages will be available to you (an advantage of python 2) and potential optimizations that could be made in your code (an advantage of python 3).
So I was getting this error
from trp import BoundingBox, Document
File "C:\Users\Kshitij Agarwal\AppData\Roaming\Python\Python39\site-packages\trp\__init__.py", line 31
print ip
^
SyntaxError: Missing parentheses in call to 'print'. Did you mean print(ip)?
This is a Python package error, in which Python2 has been used and you are probably running this on Python3.
One solution could be to convert Python2 print something to Python3 print(something) for every line in each file in the package folder, which is not a good idea😅. I mean, you can do it but still there are better ways.
To perform the same task, there is a package named 2to3 in Python which converts Python2 scripts to Python3 scripts. To install it, execute the 👇 command in terminal..
pip install 2to3
Then change the directory in terminal to the location where the package files are present, in my case - C:\Users\Kshitij Agarwal\AppData\Roaming\Python\Python39\site-packages\trp
Now execute the command 👇
2to3 . -w
and voila, all the Python2 files in that directory will be converted to Python3.
Note:- The above commands hold true for other operating systems as well. Only Python package path will vary as per the system.
print "text" is not the way of printing text in python as this won't work
print("text") will print said text on your screen in the command line

Verifying python version in a script is stopped by SyntaxError

Using features from newer python versions, e.g. f-string debugging feature: f'{some_var=}', results into a SyntaxError.
Suppose I have a python script which I would like to provide, and the user executes said script with an old python version, he will just get this error. Instead I would like to provide him with some meaningful text, e.g. "Please update python to version >=3.7"
I can solve it with a main file, which checks the version and then imports my script.
Is there a way to achieve this, while still having only a single file script?
Possible approaches:
Check sys.version or platfrom.python_version_tuple
-> Not possible, SyntaxError gets in the way, as python parses whole files
Use eval to determine SyntaxError: -> Not possible for same reasons
try:
a = "hello"
eval("f'{a=}'")
except SyntaxError:
raise ImportError('Update your Python version!!!!')
Can I trick Python somehow to not syntactically check the whole file?
(I could "pack" the whole file into a string, check for the version and then eval the string, but that is not a very clean solution and it is terrible for development)
Edit:
This question is not about "HOW to check for python version". Instead it is about "How to check for python version, before I receive SyntaxError due to new features.
I can think of one potential solution for this, where you wrap your entire script in a triple-quoted string (you'll need to make sure that it doesn't conflict with any triple-quoted strings in your script), and pass that to exec, like so:
import sys
if sys.version_info < (3, 7):
raise ImportError("I need python 3.7 or higher to run!")
exec('''
# your entire script
''')
... at this point I recommend either just using two files, or documenting on your website or wherever what the syntax error means.

Syntax error only in python 3

I have the following code which runs fine on python 2 but throws error on python 3
import sys
if sys.version_info > (3,):
#print("Python 3")
#Try Block
except urllib2.HTTPError as err:
else:
#print "Python 2" # Throws error on python 3
#Try Block
except urllib2.HTTPError, err: # Throws error on python 3.
The above code returns "Python 2" in python 2, but throws syntax error on python 3 (For python 2 syntax ).
Can anyone tell me why is this happening ? And what is the work around to fix those syntax errors in python 3 ?
Note : I am aware of print syntax on Python 3
Thanks you!
The problem is that the parser runs before any code is evaluated at runtime. Your check sys.version_info > (3,) runs at run time, after the code was already parsed and compiled. So doing such checks, you are able to make changes at runtime, but that does not help you when dealing with syntax changes.
The syntax is parsed and compiled before any code is interpreted, that is why you get syntax errors even for code that is never run at runtime.
If you are trying to create a polyglot script that is able to run on both Python 3 and Python 2, then you will need to make sure to use a syntax that works on both. For print in particular, you can import the print function in Python 2, so you can use it just like you would in Python 3:
from __future__ import print_function
Some newer features won’t work that way (for example everything async), but for the most part, you can make it work somehow.
If you end up depending on stuff with Python 3 that requires Python 2-incompatible syntax, then you could put that into a separate module and import that module conditionally at runtime. That way it won’t be loaded for Python 2, so the Python 2 parser wouldn’t attempt to load the incompatible syntax.
As for why Python 2 does not throw an error, that’s actually very simple: print('foo bar') is valid syntax in Python 2, even with the print statement. That is because you can put parentheses around anything without impacting the value. So what you actually do there is this:
print ('foo bar')
^^^^^
print statement
^^^^^^^^^^^
value, wrapped in parentheses (that don’t do anything)
That’s also the reason, why the following produces different results in Python 3 and 2:
print('foo', 'bar')
In Python 3, you get foo bar as the output, while Python 2 gives you ('foo', 'bar'). That is because the comma inside the parentheses now makes this a tuple, so you pass a tuple to the print statement. – Importing the print function fixes this to give you the same behavior on Python 2 as on Python 3.
Even though the line print "Python 2" will never be executed in Python 3, it will still be compiled to byte code (or at least attempted). That line is a syntax error in Python 3, which requires the printed items to be in parentheses. Look up the documentation for more details: other changes to print were also made.
So remove the error. Make the line
print("Python 2") # Throws error on python 3
instead. That way it works in both Python 2 and in 3. There are many sites that discuss how to write code that executes in both versions of Python. The parentheses are merely ignored in version 2 but are needed in version 3. This works if you print only one item: more than one gets more complicated.
There is another way to do printing in both versions, using from __future__ import print_function but the way I showed is easier.
Note that your attempted comment in the line is also not proper Python syntax. Change the // to # and it works.

Python 3: tokenize library changes

According to this: http://code.activestate.com/lists/python-list/413540/, tokenize.generate_tokens should be used and not tokenize.tokenize.
This works perfectly fine in Python 2.6. But it does not work anymore in Python 3:
>>> a = list(tokenize.generate_tokens(io.BytesIO("1\n".encode()).readline))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib/python3.2/tokenize.py", line 439, in _tokenize
if line[pos] in '#\r\n': # skip comments or blank lines
However, also in Python 3, this works (and returns also the desired output):
a = list(tokenize.tokenize(io.BytesIO("1\n".encode()).readline))
According to the documentation, it seems like tokenize.tokenize is the new way to use this module: http://docs.python.org/py3k/library/tokenize.html. tokenize.generate_tokens isn't even documented anymore.
But, why is there still a generate_tokens function in this module, if it's not documented? I haven't found any PEP regarding this.
I'm trying to maintain a code base for Python 2.5-3.2, should I call generate_tokens for Python 2 and tokenize for Python 3? Aren't there any better ways?
generate_tokens seems to be really a strange thing in Python 3. It doesn't work like in Python 2. However, tokenize.tokenize behaves like the old Python 2 tokenize.generate_tokens. Therefore I wrote a little workaround:
import tokenize
if sys.hexversion >= 0x03000000d:
tokenize_func = tokenize.tokenize
else:
tokenize_func = tokenize.generate_tokens
Now I just use tokenize_func, which works without problems.
generate_tokens in python3 is undocumented but not uncommented. it's there for backward compatibility, so you can use it, but it's probably better to use the changed tokenize instead...

Working around Python bug in different versions

I've come across a bug in Python (at least in 2.6.1) for the bytearray.fromhex function. This is what happens if you try the example from the docstring:
>>> bytearray.fromhex('B9 01EF')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: fromhex() argument 1 must be unicode, not str
This example works fine in Python 2.7, and I want to know the best way of coding around the problem. I don't want to always convert to unicode as it's a performance hit, and testing which Python version is being used feels wrong.
So is there a better way to code around this sort of problem so that it will work for all versions, preferably without slowing it down for the working Pythons?
For cases like this it's good to remember that a try block is very cheap if no exception is thrown. So I'd use:
try:
x = bytearray.fromhex(some_str)
except TypeError:
# Work-around for Python 2.6 bug
x = bytearray.fromhex(unicode(some_str))
This lets Python 2.6 work with a small performance hit, but 2.7 shouldn't suffer at all. It's certainly preferable to checking Python version explicitly!
The bug itself (and it certainly does seem to be one) is still present in Python 2.6.5, but I couldn't find any mention of it at bugs.python.org, so maybe it was fixed by accident in 2.7! It looks like a back-ported Python 3 feature that wasn't tested properly in 2.6.
You can also create your own function to do the work, conditionalized on what you need:
def my_fromhex(s):
return bytearray.fromhex(s)
try:
my_fromhex('hello')
except TypeError:
def my_fromhex(s):
return bytearray.fromhex(unicode(s))
and then use my_fromhex in your code. This way, the exception only happens once, and during your runtime, the correct function is used without excess unicode casting or exception machinery.

Categories

Resources