Python update running code
I’m working on a project and I need help.
I have a Raspberry Pi that is connected to a small display. I want the display to show the current moon phase, I’ve already downloaded all the images, labeled 000.png to 360.png. The numbers stand for the relative phase angle of the current moon.
I’ve managed to create a script that scrapes the phase angle from a website and puts it in a json file.
[]So what needs to happen next is I need to update the image currently being shown, in this case I would be showing in my python script image /269.png but I want that filename to update to the latest number from the json file, so in this case update to /270.png
I have this code that creates the path: (I’m new in python and generally not good with coding)
path = "near_side_1024x1024x8/" with open('number.json', 'r') as f: distros_dict = json.load(f) for distro in distros_dict: op = json.dumps(distro["text"]) str = path+op+".png" print(str)
This results in: near_side_1024x1024x8/270.png
But now I’m stuck, I’ve tried tkinter and pygame, and I’ve managed to get the image to display fullscreen but what I have not accomplished is to have the image update when new phase angle value has been fetched, what do I need to do in python to run the code again to update the image after lets say 10 min? Or when a change in the json file is detected? Is there some loop function?
At the moment the only way for me to update the image is by closing the python script and running it again.
I hope I’ve explained this well enough. I’m very new in python and programming in general.
deanhystad
def update_phase(): with open('number.json', 'r') as f: distros_dict = json.load(f) for distro in distros_dict: op = json.dumps(distro["text"]) str = path+op+".png" # Open file and update image # Repeat in an hour 3,600,000 milliseconds root.after(3600000, update_phase)
(Jul-06-2022, 01:12 PM) deanhystad Wrote: You need a periodic event. In tkinter you could use .after() to call a function.
def update_phase(): with open('number.json', 'r') as f: distros_dict = json.load(f) for distro in distros_dict: op = json.dumps(distro["text"]) str = path+op+".png" # Open file and update image # Repeat in an hour 3,600,000 milliseconds root.after(3600000, update_phase)
Error:AttributeError: type object 'str' has no attribute 'read'
deanhystad
line 6 str is a python built in. You are re-assigning it. Maybe something like my_string = str(my_path) Not sure if that is the problem but, maybe one of the more experienced can help better.
I welcome all feedback.
The only dumb question, is one that doesn’t get asked.
deanhystad
That is bad programming making a built-in function unavailable, but it is not the reason for the error. Somewhere, in code we haven’t been shown, somebody is trying to use a filename as though it were a file object (my best guess).
Here’s the full code and error:
import json import os import tkinter import PIL import PIL.Image import tkinter as tk from PIL import Image, ImageTk import numpy as np path = "near_side_1024x1024x8/" def update_phase(): with open('number.json', 'r') as f: distros_dict = json.load(f) for distro in distros_dict: op = json.dumps(distro["text"]) str = path+op+".png" # Open file and update image # Repeat in an hour 3,600,000 milliseconds root.after(3600000, update_phase) import sys if sys.version_info[0] == 2: # the tkinter library changed it's name from Python 2 to 3. import Tkinter tkinter = Tkinter #I decided to use a library reference to avoid potential naming conflicts with people's programs. else: import tkinter from PIL import Image, ImageTk def showPIL(pilImage): root = tkinter.Tk() w, h = root.winfo_screenwidth(), root.winfo_screenheight() root.overrideredirect(1) root.geometry("%dx%d+0+0" % (w, h)) root.focus_set() root.bind("", lambda e: (e.widget.withdraw(), e.widget.quit())) canvas = tkinter.Canvas(root,width=w,height=h) canvas.pack() canvas.configure(background='black') imgWidth, imgHeight = pilImage.size if imgWidth > w or imgHeight > h: ratio = min(w/imgWidth, h/imgHeight) imgWidth = int(imgWidth*ratio) imgHeight = int(imgHeight*ratio) pilImage = pilImage.resize((imgWidth,imgHeight), Image.ANTIALIAS) image = ImageTk.PhotoImage(pilImage) imagesprite = canvas.create_image(w/2,h/2,image=image) root.mainloop() pilImage = Image.open(str) showPIL(pilImage)
Error:^CHermanns-MacBook-Pro:test hermann$ python3 tkinter1.py Traceback (most recent call last): File "/Users/hermann/.pyenv/versions/3.9.0/lib/python3.9/site-packages/PIL/Image.py", line 3072, in open fp.seek(0) AttributeError: type object 'str' has no attribute 'seek' During handling of the above exception, another exception occurred: Traceback (most recent call last): File "/Users/hermann/Dropbox/electronics/moon/test/tkinter1.py", line 52, in pilImage = Image.open(str) File "/Users/hermann/.pyenv/versions/3.9.0/lib/python3.9/site-packages/PIL/Image.py", line 3074, in open fp = io.BytesIO(fp.read()) AttributeError: type object 'str' has no attribute 'read'
deanhystad
Sorry Menator, you were right.
The str() function is being used as a str object in line 52. Previously the program «corrected» this by reassigning the «str» variable to reference a string instead of a function.
str = path+op+".png" # This changes str from referencing a function to a string
The code is all wrong for a display that will update over time. It should create the tkinter window first, then call a periodic function to get the moon phase and load the proper image.
import json import tkinter import tkinter as tk from PIL import Image, ImageTk import numpy as np path = "near_side_1024x1024x8/" def update_phase(): """Retrieve moon phase and update image""" with open("number.json", "r") as f: distros_dict = json.load(f) for distro in distros_dict: op = json.dumps(distro["text"]) # Open file and update image showPIL(path + op + ".png") # Run myself again after an hour (3,600,000 milliseconds) root.after(3600000, update_phase) def showPIL(filename): """Open image file and draw image on canvas""" pilImage = Image.open(filename) imgWidth, imgHeight = pilImage.size if imgWidth > w or imgHeight > h: ratio = min(w / imgWidth, h / imgHeight) imgWidth = int(imgWidth * ratio) imgHeight = int(imgHeight * ratio) pilImage = pilImage.resize((imgWidth, imgHeight), Image.ANTIALIAS) image = ImageTk.PhotoImage(pilImage) imagesprite = canvas.create_image(w / 2, h / 2, image=image) root = tkinter.Tk() w, h = root.winfo_screenwidth(), root.winfo_screenheight() root.overrideredirect(1) root.geometry("%dx%d+0+0" % (w, h)) root.focus_set() root.bind("", lambda e: (e.widget.withdraw(), e.widget.quit())) canvas = tkinter.Canvas(root, width=w, height=h) canvas.pack() canvas.configure(background="black") update_phase() # Starts the update loop root.mainloop()
Saved searches
Use saved searches to filter your results more quickly
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session. You switched accounts on another tab or window. Reload to refresh your session.
A runtime python code manipulation framework for profiling, debugging and bugfixing
License
devopspp/pyliveupdate
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Name already in use
A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
Sign In Required
Please sign in to use Codespaces.
Launching GitHub Desktop
If nothing happens, download GitHub Desktop and try again.
Launching GitHub Desktop
If nothing happens, download GitHub Desktop and try again.
Launching Xcode
If nothing happens, download Xcode and try again.
Launching Visual Studio Code
Your codespace will open once ready.
There was a problem preparing your codespace, please try again.
Latest commit
Git stats
Files
Failed to load latest commit information.
README.md
PyLiveUpdate is tool to help you modify your running python code without stopping it. It is useful for modifying long-running server programs in production with zero downtime. Some modification scenario includes: inject code to profile the runtime of certain lines of code; inject code to print out a variable for debugging; apply a patch without restarting.
Put these two lines of code in your server program and run it. Try it out with example/program1.py .
from pyliveupdatescripts import UpdateStub UpdateStub().start()
Start a controller to modify it!
> pylu-controller -l 127.0.0.1:50050
Some predefined modification available in the controller
> FuncProfiler.profile(['__main__.**', 'module1.**']) # inject execution time profiling code into all functions in __main__ and module1 > LineProfiler.profile('__main__.bar', [11, 12]) # inject time profiling code into certain lines > FuncDebugger.debug('__main__.bar') # inject code to print out function parameter and return value > LineDebugger.debug('__main__.bar', [11, 12]) # inject code to print out variables in certain lines > VarDebugger.debug('__main__.bar', 'b') # inject code to print out all values of a variable in different statements
These will print out corresponding profiling and debugging info in the program terminal and in /tmp/pyliveupdate . You can also define your own customized modifications.
There are in general two kinds of modification: instrument and redefine. You can define them as following and apply with patch(‘patch.py’) . Try it out with example/patch.py .
Instrument code into existing functions
from pyliveupdate.update import Instrument, UpdateManager def _line_after(a): print(a) update = Instrument('__main__.bar', <('line_after', [12, 14]): _line_after>) UpdateManager.apply_update(update)
The code injects a print(a) in line 12 and 14 in function __main__.bar .
Redefine (patch) existing functions
from pyliveupdate.update import Redefine, UpdateManager def new_bar(a): print('new_bar', a) update = Redefine('__main__', None, ) UpdateManager.apply_update(update)
The code redefines __main__.bar with new_bar .
PyLiveUpdate also support to revert a modification on the fly:
> LU.ls() # list all modification > LU.revert(1) # revert modifation with id 1
PyLiveUpdate also comes with some handy tools based on it:
Dynamically choose functions or lines to profile and show the result with a flamegraph.
- Start your program with PyLiveUpdate enabled, like example/patch.py .
- Start a controller pylu-controller -l 127.0.0.1:50050
- Start profiling functions with FP.profile([‘__main__.**’, ‘module1.**’]) or lines with LineProfiler.profile(‘__main__.bar’, [11, 12]) .
- Process the logs with pylu-processlogs -i /tmp/pyliveupdate.log in another terminal It will generated a flamegraph and a summary:
The following summary gives in process 4510 thread 5 , views.results was called 10 times and each time takes 139 ms , views.results called manager.all for 20 times.
4510-Thread-5 function hit time/hit (ms) views.results 10 138.562 -manager.all 20 14.212 -__init__.__hash__ 10 0.035 -manager.get_queryset 20 0.922 -query.__init__ 20 0.616 -query.__init__ 20 0.071
Please kindly cite our work as follows if you want to refer to it in any writing:
@inproceedings$:$\$ Code Change for Python-based Online Services>, author=, booktitle=, pages=, year= >
About
A runtime python code manipulation framework for profiling, debugging and bugfixing