I'm attempting to set the numpy print options using a signal handler on the window resize event. Don't want to make the connection until numpy has been imported, and don't want to import numpy automatically at python startup. I've got it almost-working with the code below:
# example.py
import wrapt
#wrapt.when_imported('numpy')
def post_import_hook(numpy):
import signal
try:
from shutil import get_terminal_size
except ImportError:
# Python 2
from shutil_backports import get_terminal_size
def resize_handler(signum=signal.SIGWINCH, frame=None):
w, h = get_terminal_size()
numpy.set_printoptions(linewidth=w)
print('handled window resize {}'.format(w))
resize_handler()
signal.signal(signal.SIGWINCH, resize_handler)
It works in vanilla python REPL (test with python -i example.py and resize the terminal a bit). But it doesn't work in ipython when the same code is added to my startup ipython config, and I don't understand why.
I'm not fixed on this particular approach (that's just what I've tried so far), so I'll phrase the question more generally:
How can numpy correctly fill to the terminal width automatically in ipython?
You can use print(np.arange(200)), for example, to check numpy's line wrapping behaviour.
Inspired by the standard fix for printing large arrays without truncation, I tried setting the line width to infinity. This seems to be working fine both in the REPL and in ipython, so I suggest this workaround:
import numpy
numpy.set_printoptions(linewidth=numpy.inf)
This doesn't explain why your fix doesn't work for ipython, but in case the above line doesn't mess with anything unexpected, it should make printing immune to resizing.
Related
I'm trying to do the same thing Marc Leese tried to do here but didn't seem to get a clear answer on (at least none that works for me): trying to convert this file to python 3 and getting the error module not found
That is, use in a Python 3+ environment the solitaire.py example code as found e.g. here: https://android.googlesource.com/toolchain/python/+/0d4194853e08d3244931523470331c00dfb94863/Python-2.7.3/Demo/tkinter/guido/solitaire.py
Specifically, I'm running Python 3.7.9 through Spyder 3.3.6.
When I try to run the above code, I first get an error that Tkinter is not found. When I correct Tkinter to tkinter, however, I still get an error that says:
ModuleNotFoundError: No module named 'Canvas'
Regardless of whether I use from tkinter import * or from tkinter import Canvas I keep getting the same error.
The whole code block in question is:
# Imports
import math
import random
from tkinter import *
from Canvas import Rectangle, CanvasText, Group, Window
# Fix a bug in Canvas.Group as distributed in Python 1.4. The
# distributed bind() method is broken. Rather than asking you to fix
# the source, we fix it here by deriving a subclass:
class Group(Group):
def bind(self, sequence=None, command=None):
return self.canvas.tag_bind(self.id, sequence, command)
I've noticed before that example code using import * did not seem to work as in the example, but before I've always managed to find a workaround.
If someone could explain what's going from here/how to fix it I'd be very much obliged!
You've copied some very old code that apparently depends on a module named "Canvas" (for example, a file named Canvas.py). This module is not part of tkinter. You will need to find the original Canvas.py file
When working with my python package, a certain function has some interactive matplotlib stuff going on.
In Jupyter Notebook I always have to use the magic %matplotlib qt to switch backend in order to make it work.
However, this might seem obvious to me, but others who're trying to work with my package this is not that straight forward.
This is what I have so far in my __init__.py:
def run_from_notebook():
return hasattr(__builtins__, '__IPYTHON__')
if run_from_notebook():
# this has no effect
try:
from IPython import get_ipython
ipython = get_ipython()
except ImportError:
import IPython.ipapi
ipython = IPython.ipapi.get()
ipython.magic("matplotlib qt")
I also tried:
if matplotlib.get_backend() != 'Qt5Agg':
matplotlib.use('Qt5Agg')
but still no effect.
Is there a way to automatically switch backend in Jupyter Notebook when someone imports my package?
and also: Is there any reason it's not considered as a good practice?
It turns out that the problem is with the run_from_notebook function. When running it simply in a notebook cell it returns True, but when it's imported from my module, it returns False. The question now is rather: How to detect if code is run inside Jupyter?
For example running manually
def switch_backend_to_Qt5():
import matplotlib
if matplotlib.get_backend() != 'Qt5Agg':
matplotlib.use('Qt5Agg')
gets the job done.
EDIT :
The following function suits my needs:
import os
def run_from_notebook():
try:
__IPYTHON__
# If it's run inside Spyder we don't need to do anything
if any('SPYDER' in name for name in os.environ):
return False
# else it's probably necessary to switch backend
return True
except NameError:
return False
I am working on a large Python program which makes use of a multitude of modules depending on command-line options, in particular, numpy. We have recently found a need to run this on a small embedded module which precludes the use of numpy. From our perspective, this is easy enough (just don't use the problematic command line options.)
However, following PEP 8, our import numpy is at the beginning of each module that might need it, and the program will crash due to numpy not being installed. The straightforward solution is to move import numpy from the top of the file to the functions that need it. The question is, "How bad is this"?
(An alternative solution is to wrap import numpy in a try .. except. Is this better?)
Here is a best practice pattern to check if a module is installed and make code branch depending on it.
# GOOD
import pkg_resources
try:
pkg_resources.get_distribution('numpy')
except pkg_resources.DistributionNotFound:
HAS_NUMPY = False
else:
HAS_NUMPY = True
# You can also import numpy here unless you want to import it inside the function
Do this in every module imports having soft dependency to numpy. More information in Plone CMS coding conventions.
Another idiom which I've seen is to import the module as None if unavailable:
try:
import numpy as np
except ImportError:
np = None
Or, as in the other answer, you can use the pkg_resources.get_distribution above, rather than try/except (see the blog post linked to from the plone docs).
In that way, before using numpy you can hide numpy's use in an if block:
if np:
# do something with numpy
else:
# do something in vanilla python
The key is to ensure your CI tests have both environments - with and without numpy (and if you are testing coverage this should count both block as covered).
When uses numpy + setproctitle, titles are truncated to 11 characters. Any ideas why is happening that?
from setproctitle import setproctitle
import numpy
setproctitle("ETL-1234567890123456789")
# It's truncated to "ETL-1234567"
If I remove numpy import it works.
It works fine on OSX but not in Ubuntu 14.04
My numpy version 1.9.0
As the docs say, setproctitle wraps up source code from Postgres that does different things on each platform.
On OS X, like most *BSD systems, just reassigning argv[0] to a pointer another string is sufficient.* But on Linux, it's not; you have to leave argv[0] pointing to the same place, and clobber that buffer (possibly rearranging the other arguments and even the environment to make space).**
* Well, not quite; you also have to change _NSGetArgv() and _NSGetEnviron().
** How does this not screw up the rest of your code that might want to access argv or env? It makes a deep copy, then reassigns your globals so the rest of your code will see that copy; only the OS sees the original buffer.
According to the comments, this has to be done "early in startup".* Touching sys.argv or sys.environ from Python shouldn't actually matter, because those operate on copies, but NumPy is written in C, and does all kinds of stuff when it's imported that could conceivably be a problem.**
* Presumably this is because other code might either keep references to arguments or env variables that are about to be clobbered, or might call functions like setenv that might themselves copy the data to a new buffer so we don't end up operating on the one the OS sees.
** It's even possible that the problem is just that NumPy imports sys or another stdlib module, and that's what causes the problem.
So, I think the answer is to make sure you call setproctitle before importing numpy—or, to be safe, any C extension modules (maybe even some of the ones in the stdlib). In other words:
from setproctitle import setproctitle
setproctitle("ETL-1234567890123456789")
import numpy
Alternatively, it may be sufficient to delay the import of setproctitle until right before you call it:*
import numpy
from setproctitle import setproctitle
setproctitle("ETL-1234567890123456789")
* The module init calls spt_setup, which does all the horrible hackery needed to find the real argv buffer. So, most likely, it's too late to do this after importing NumPy. But possibly, it's OK to do it, and the problem is only problem is the results changing before you use them.
But either way, don't do anything between the import and the call.
(If this doesn't work, let me know and I'll research further and/or delete the answer.)
I have a small script in python2.7 that I want to convert into Windows executable. I use pyinstaller for this.
The script:
import sys
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
def get_inputs():
coor = raw_input(">>>top x left: ").replace(" ", "")
top, left = coor.split("x")
top = int(top.strip())
left = int(left.strip())
return top, left
def plot_location(top, left):
img= mpimg.imread('nbahalfcourt.jpg')
plt.imshow(img)
plt.scatter(left, top)
plt.grid()
plt.show()
def main():
top, left = get_inputs()
plot_location(top, left)
if __name__ == '__main__':
print "Input top x left coordinates (no space) eg: 44x232"
run = True
while run:
main()
Basically, the script just plots a point on a grid.
The converting process finishes successfully. When I run the .exe however I've got the ImportError (see below) even though I have no reference to Tkinter anywhere.
What could went wrong here?
I have a feeling that matplotlib uses the Tkinter module internally, but imports it in a non-standard way. Then pyinstaller doesn't notice Tkinter is needed, and subsequently doesn't bundle it into the executable.
Try explicitly putting import Tkinter at the top of your script.
I had the same issue and none of the solutions here worked. I was using Pyinstaller 3.2 (the latest version at the time) and everything was fixed (and no import statements needed) when I upgraded to the latest developer version using
pip install https://github.com/pyinstaller/pyinstaller/archive/develop.zip
This seems to indicate that at the times of writing this that all the kinks to this issue are still being worked out
EDIT: As of January 15 2017 Pyinstaller version 3.2.1 was released. I now use this and it solves this issue along with others like this and this that I could previously only solve by using the developer version. So I highly recommend upgrading to the latest version if you haven't already.