Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make the backend work inside a Docker container #11

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

ayorgo
Copy link
Contributor

@ayorgo ayorgo commented Aug 22, 2023

This addresses #10 by using kitty's low level graphics protocol.

The main challenge was to get the window dimensions in pixels as described here which was solved with the help of this SO answer.


with BytesIO() as buf:
self.canvas.figure.savefig(buf, format='png', facecolor='#888888')
icat('--align', 'left', output=False, input=buf.getbuffer())
write_chunked(a='T', f=100, data=buf.getvalue())
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Was getting the following error with getbuffer():

BufferError: Existing exports of data: object cannot be re-sized

Reproducible example:

import io
with io.BytesIO() as buf:
    buf.write(b'hello')
    res = buf.getbuffer()

@kovidgoyal
Copy link

You dont need to use an escape code to get the size, use the example code from the graphics protocol docs:

import array, fcntl, sys, termios
buf = array.array('H', [0, 0, 0, 0])
fcntl.ioctl(sys.stdout, termios.TIOCGWINSZ, buf)
print((
    'number of rows: {} number of columns: {}'
    'screen width: {} screen height: {}').format(*buf))

This code is what icat uses as well, so if icat worked so will this.

@ayorgo
Copy link
Contributor Author

ayorgo commented Aug 25, 2023

Thanks for the feedback and the amazing terminal emulator @kovidgoyal. The recipe didn't quite work for me inside a Docker container sadly. It manages to get rows and columns just right but the height and width in pixels are both zeros despite me having specified -e DISPLAY -v /tmp/.X11-unix:/tmp/.X11-unix as well as -v /usr/lib/kitty/terminfo/x:/root/.terminfo/x although I'm not particularly happy with forcing people to install kitty itself inside containers. The escape code on the other hand works quite well both inside and outside of a container.

@kovidgoyal
Copy link

kovidgoyal commented Aug 25, 2023 via email

@ayorgo
Copy link
Contributor Author

ayorgo commented Aug 25, 2023

SSH into your container and it will work.

Fair enough although that requires some extra steps like opening the ssh port, having the ssh server installed and configured inside the container, a firewall properly setup, then running the ssh command itself with some parameters.

While technically viable I'd argue that it isn't the simplest solution for a lay person like e.g. myself (and some of my data science colleagues as well) whereas the proposed solution with the escape code while a bit cumbersome to implement works straight away without any extra steps.

@kovidgoyal
Copy link

Well, the correct solution is of course, to get docker to fill in the winsize struct properly in their pseudo terminal implementation. Then you wont have to jump through these hoops. In the meantime, I suggest using the ioctl first and falling back to the escape code only if it returns zero. That way people not running inside docker dont pay the price.

@ayorgo
Copy link
Contributor Author

ayorgo commented Aug 25, 2023

Well, the correct solution is of course, to get docker to fill in the winsize struct properly in their pseudo terminal implementation. Then you wont have to jump through these hoops. In the meantime, I suggest using the ioctl first and falling back to the escape code only if it returns zero. That way people not running inside docker dont pay the price.

Makes perfect sense. I'll look into how to pass pixel dimensions to a container.

Just curious, what do you mean by "pay the price"? Is the escape code method slower than the one with ioctl?

@kovidgoyal
Copy link

Yes, much slower. Escape code means the kernel has to send the escape code from your program to the terminal over a tty device, the terminal has to parse it and then the kernel has to send the terminals reply to your program again over a tty device, which then has to parse that reply. And say the user is running this program over SSH then there is basically unbounded latency depending on the speed and quality of the network link.

By contrast the ioctl() is a single context switch into the kernel which copies the cached winsize struct into your programs memory.

@ayorgo ayorgo force-pushed the docker branch 3 times, most recently from 919f6ff to 349e776 Compare September 8, 2023 08:31

# account for post-display prompt scrolling
# 3 line shift for [\n, <matplotlib.axes…, >>>] after the figure
px[1] -= int(3*(px[1]/rows))
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Didn't really see the point of the post-display prompt scrolling. Can change it back if the maintainers insist.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants