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

How to use MemoryFS() to write/open files directly #563

Closed
NebularNerd opened this issue Feb 5, 2023 · 8 comments
Closed

How to use MemoryFS() to write/open files directly #563

NebularNerd opened this issue Feb 5, 2023 · 8 comments

Comments

@NebularNerd
Copy link

Hi there,

I'm working on a small project for myself using customtkinter, one of the quirks of TK over PySimpleGUI is it's dislike of using PNG's as icons on Windows. To keep everything in one file I typically store a PNG(s) in the .py as a base64 strings, I can convert it to both a real PNG and ICO file using the below code:

    def base64tofile():
        # Lets make some temp files from our base64 data, wm_iconbitmap and iconbitmap do not like base64 😐
        app = Image.open(BytesIO(base64.b64decode(app_icon)))
        app.save(ytico_ico, "ico")
        app.save(ytico_png, "png")

At present I'm using tempfile to save the resulting two files which TK is happy to use and then delete them, at least that's the idea as trying to shutil.rmtree(tempdir) on exit keeps giving file locks.

Again due to TK weirdness you can't pump a base64 string into some of their variables such as root.wm_iconbitmap or root.iconbitmap they have to be files (they should fix this 😐). So I thought I would try to avoid real files with pyfilesystem's MemoryFS() but I'm struggling to make sense of it, it's not heavily used (but it should be) so examples are thin on the ground.

Can someone help with how I write these two files in app.save to memory? I've got as far as;

import fs
mem_fs = fs.open_fs('mem://')

But I cannot figure out how to write/open files like a regular path, in this example above I need to write to mem://ytico.ico then call it back as a proper file later on, I guess for opening I can use icon = mem_fs.open('ytico.ico') but again not sure.

TL:DR;
How can I treat mem_fs as a regular path style equivalent to `c:\doc\myfile.txt'

@lurch
Copy link
Contributor

lurch commented Feb 5, 2023

You can't, but see the comments in #541

@NebularNerd
Copy link
Author

Thanks @lurch,

I'll have to rethink this idea, while openbin could partially solve the issue, it's a limitation of TK that anything that is not a proper path is rejected as valid input. For my own use it's not world ending as my Temp folder is actually mapped to a Ramdrive under Windows, however I try avoid temp files and such where possible. If TK accepted PNG's under Windows and base64 strings I could avoid a lot of the effort needed just to display an icon.

@lurch
Copy link
Contributor

lurch commented Feb 6, 2023

You might be interested to read about the auto_clean option of TempFS https://docs.pyfilesystem.org/en/latest/reference/tempfs.html 🙂

@NebularNerd
Copy link
Author

I've been using various combinations of that but for some reason Windows really really does not want to let go of the files while the .py is running. Not sure what has made it that way, tried a few things and it's refusing to let go of the files until Python has stopped completely. I've got another idea in mind that might work just got to find the solution...

@lurch
Copy link
Contributor

lurch commented Feb 6, 2023

Perhaps TK has a lock on the files, and so you somehow need to "unload" TK, before you try and close (and auto-delete) the TempFS? 🤷

@NebularNerd
Copy link
Author

Yea that's the case, as soon as Python has finished you can delete them. I've tried all sorts of variants of .close() and such but something's blocking it. As I say, if TK just accepted base64 strings I would be good to go, convert the PNG base64 string to an ICO base64 string, then pass that string in as the file, but no, that would be too easy 🤣

@lurch
Copy link
Contributor

lurch commented Feb 6, 2023

Do none of these work? https://www.google.com/search?q=python+unload+module
(It's not something I've ever needed to try myself)

@NebularNerd
Copy link
Author

Thanks for the suggestion, I worked through some of those then it dawned on me, it had worked until I introduced ctypes to fix the Windows taskbar icon. Well that just led to a whole bunch of fun 🤣

Short version, I had to create a 'death loop' that:

  • set the icon variable to another icon (using a Python icon from the python<x.xx>\dll folder, if any Win user runs the script they'll have that icon on their system)
  • run the ctypes again to set the new icon as the one it wants to look at
  • kill the GUI
  • but then loop back round to almost start the GUI to take attention away from the temp icon (but no GUI shows)
  • then kill it again 💥
  • success 🎉

This all happens in a near instant so that's a bodge-tastic win, thanks for the suggestions @lurch it gave me enough to create the insanity required to do the job. Will be putting forward suggestions to TK about supporting both base64 and an internal png>ico converter for win users.

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

No branches or pull requests

2 participants