NameError when putting variable declaration in if __name__ == '__main__': [duplicate] - python

This question already has an answer here:
How to process requests from multiiple users using ML model and FastAPI?
(1 answer)
Closed 15 days ago.
I have a Python file named main.py. I am running it on Python 3.9.13 on Windows.
import uvicorn
from fastapi import FastAPI
app = FastAPI()
#app.post('/c')
async def c(b: str):
print(a)
if __name__ == '__main__':
a = load_embeddings('embeddings')
uvicorn.run('main:app', host='127.0.0.1', port=80)
Running this, then invoking POST /c will cause a 500 error with NameError 'a' is not defined.
However it is obvious that a will be defined first before the server is ran. If I move a outside of the if __name__ == '__main__': then it works, but it causes load_embeddings to be ran multiple times for unknown reasons (3 exact). Since load_embeddings for me takes long time, I do not want the duplicate execution.
I wish to look for either of these as a solution to my issue: stop whatever outside if __name__ == '__main__': from executing multiple times, OR make a defined globally when it is being defined under if __name__ == '__main__':.
Note: variable names are intentionally renamed for ease of reading. Please do not advise me anything on coding style/naming conventions. I know the community is helpful but that's not the point here, thanks.

You can resolve the issue by moving the a variable definition inside the c function. Then, you can add a check inside the function to load the embeddings only if they have not been loaded yet. You can achieve this by using a global variable, which will keep track of whether the embeddings have been loaded or not.
Here is an example:
import uvicorn
from fastapi import FastAPI
app = FastAPI()
EMBEDDINGS_LOADED = False
def load_embeddings(filename):
# Load embeddings code here
...
#app.post('/c')
async def c(b: str):
global EMBEDDINGS_LOADED
if not EMBEDDINGS_LOADED:
load_embeddings('embeddings')
EMBEDDINGS_LOADED = True
print(a)
if __name__ == '__main__':
uvicorn.run('main:app', host='127.0.0.1', port=80)

Related

Calling Functions in Flask

Apologies in advance as this is probably the most basic question to be found here but I'm the greenest of newbies and cannot get my head around how to call a function in flask so it runs when I land on the URL.
My purpose is to try and get a python script to run when a GET request is made to the URL from WebCore (for those who don't know it's a program that allows you to code smart home functionality for SmartThings) or when I simply land at the URL. I will then tie this to a virtual switch which will start the code which controls a motor in a cat feeder so I can feed my cat remotely/by voice.
All very frivolous stuff but trying to learn some basics here, can anyone help?
As it stands I have two files, both in a root directory named 'CatFeeder'
catfeeder.py
from flask import Flask
from feed import start
app = Flask(__name__)
#app.route('/')
def feed()
return feed.start
if __name__ == '__main__':
app.run(host='0.0.0.0', port='5000', debug=True)
feed.py
import time
import RPi.GPIO as GPIO
def start():
# Next we setup the pins for use!
GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)
Motor1Forward = 17
Motor1Backwards = 18
GPIO.setup(Motor1Forward,GPIO.OUT)
GPIO.setup(Motor1Backwards,GPIO.OUT)
print('Feeding Lola')
# Makes the motor spin forward for x seconds
# James Well Beloved - 11 seconds = 28g food (RDA Portion = 52g/4kg cat or 61g/5kg cat)
# XXXX - X seconds - Xg food
GPIO.output(Motor1Forward, True)
GPIO.output(Motor1Backwards, False)
time.sleep(11)
print('Lola Fed!')
GPIO.output(Motor1Forward, False)
GPIO.output(Motor1Backwards, False)
GPIO.cleanup()
quit()
When I set export FLASK_APP=catfeeder.py and then flask run the service runs but nothing happens when I land on the page. I assume there is something wrong in the way I am calling things.
I guess it would be easiest if I just integrated the code from feed.py into catfeeder.py but I wasn't sure what the syntax would be for this and it felt like a messy way to go about it.
Thanks in advance!
you've imported the function but didn't actually invoke it as you missed adding your brackets (), try return start()
In case you meant to return a function object and not invoke the function, you should return it by typing return start

where to open and close file in web.py

A data file was getting corrupted when I terminated the program and realised that it was never properly closed.
It is quite critical that it does not get corrupted. So I added a statement to close the file.
Now, it seems like the file gets opened twice and then closed. That's one operation too many. There are of course many read-write operations in-between but it should only open and close the files once.
Here is what I have done to the standarize web.py template:
import web
import pandas as pd
store = pd.HDFStore('data_file.h5')
urls = (
'/', 'index'
)
class index:
def __init__(self):
self.__df = store['df']
def GET(self):
# several read-write, and modify operations on self.__df
return "Hello, world!"
if __name__ == "__main__":
try:
app = web.application(urls, globals())
app.run()
finally:
store.close()
Now, if I move the line which opens the store down inside the try statement at the bottom, it complains since it compiles the class but I can't find the variable store.
I tried initialising store with None at the top but it didn't work either. Then I tried putting that line up at the top in the function and calling it from the bottom, however, that didn't bring it into scope.
I was thinking of making it a global variable, which would probably do the trick, is that the right approach?
See web.py running twice. As mentioned there, avoid using globals as they don't do what you think they do... app.py runs twice, once on startup and a second time within web.appplication(urls, globals()). If you set autoreload=False in web.applications() call, it won't load the file twice.
Another solution is to attach your store to web.config, which is globally available.
if __name__ == "__main__":
try:
web.config.store = pd.HDFStore('data_file.h5')
app = web.application(urls, globals())
app.run()
finally:
web.config.store.close()
...and reference that global in your __init__
class index:
def __init__(self):
self.__df = web.config.store['df']

Globale Variables with Bottlpy (in background)

i need to use global variables in my program with either flask or bottle running as a webservice. so far im using bottle as a thread with a snippet i found here: Starting python bottle in a thread/Process and another daemon next to it
i basically want to go to localhost:8080/hello to increase the global variable test by one:
#!/usr/bin/env python
from bottle import route, run
from multiprocessing import Process
#route('/hello')
def hello():
global test
test = test + 1
return test
def main():
global test
test = 0
t = Process(target=bottle.run(host='0.0.0.0', port=8080))
t.daemon = True
t.start()
while(True)
print test
time.sleep(0.5)
if __name__ == "__main__":
main()
if i go to localhost:8080/hello with my browser i get:
Error 500: Internal Server Error - Unhandled Exception
i cant see the exception tho, even with
try
global test
test = test + 1
return test
except Exception e
print e
You're returning an int from hello, but you need to return an iterable (of strings).
Tip: add debug=True to your call to run to get better error info in your response.
t = Process(target=run(host='0.0.0.0', port=8080, debug=True))

How do I make a module think its name is __main__? [duplicate]

This question already has answers here:
How to make __name__ == '__main__' when running module
(4 answers)
Closed 6 years ago.
I have a python script (actually, lots of scripts) with code that is executed only when this module is run as the main script:
if __name__ == '__main__':
print("I am the main script")
But now I want a testing script to load them as modules, so that it can then poke in their internal state. Rewriting (to turn the code block into a function) is not an option. How do I import a module in such a way that it thinks its name is __main__? I'm sure I've seen this done before, with the help of some import library or other, but it's not coming up in my searches.
You'd have to bypass the import machinery, and use exec instead:
import imp
main = imp.new_module('__main__')
with open(module_filename, 'r') as source:
exec(source.read(), vars(main))
Demo:
>>> source = '''\
... if __name__ == '__main__':
... print("I am the main script")
... '''
>>> import imp
>>> main = imp.new_module('__main__')
>>> exec(source, vars(main))
I am the main script
Rather than go this route, consider creating a function you call from the __main__ guard instead, so you can just import that function for testing:
def main():
print("I am the main script")
if __name__ == '__main__':
main()

Importing values in config.py

I wanted to mix a config.py approach and ConfigParser to set some default values in config.py which could be overridden by the user in its root folder:
import ConfigParser
import os
CACHE_FOLDER = 'cache'
CSV_FOLDER = 'csv'
def main():
cp = ConfigParser.ConfigParser()
cp.readfp(open('defaults.cfg'))
cp.read(os.path.expanduser('~/.python-tools.cfg'))
CACHE_FOLDER = cp.get('folders', 'cache_folder')
CSV_FOLDER = cp.get('folders', 'csv_folder')
if __name__ == '__main__':
main()
When running this module I can see the value of CACHE_FOLDER being changed. However when in another module I do the following:
import config
def main()
print config.CACHE_FOLDER
This will print the original value of the variable ('cache').
Am I doing something wrong ?
The main function in the code you show only gets run when that module is run as a script (due to the if __name__ == '__main__' block). If you want that turn run any time the module is loaded, you should get rid of that restriction. If there's extra code that actually does something useful in the main function, in addition to setting up the configuration, you might want to split that part out from the setup code:
def setup():
# the configuration stuff from main in the question
def main():
# other stuff to be done when run as a script
setup() # called unconditionally, so it will run if you import this module
if __name__ == "__main__":
main() # this is called only when the module is run as a script

Categories

Resources