web.py: avoid global instances? - python

the last few weaks, I am playing a little bit with the Web.py framework. As my application is now getting bigger and bigger, I want to restructure the sourcecode and put code fragments in different classes. Now, I don't really know where I should create my object instances if I need them in different web.py classes. Let us assume, my sourcecode looks like:
import web
import myclass
urls = (
'/', 'index',
'/test', 'test'
)
#should i make my instance global...
my = myclass.myClass()
class test:
def __init__(self):
#...or should i make my instance local: my = myclass.myClass()
pass
def GET(self):
item = my.getItem()
return item
def POST(self):
pass
class index:
def __init__(self):
#...or should i make my instance local: my = myclass.myClass()
pass
def GET(self):
date = my.getDate()
return date
if __name__ == "__main__":
app = web.application(urls, globals())
app.run()
Now, I want to access the methods getItem() and getDate() (which belong to the instance my), if the appropriate sites in my webbrowser are called. My question is now: Should I make the instance global or is it better, if I make it local? I really don't like global instances, but I don't see any other way as to make it global. Sure, it would be possible, to create a local instance, but then, every time the page loads, a new instance would be created, right? Normally, this wouldn't be a problem, but myclass accesses a serial port, so I need to make sure, that only one instance is created.
Am I missing something or is a global instance the only possible solution to accomplish this?

After some research, I came to the conclusion, that global instances are the way to go here. However, one must be careful with global instances if they are used together with the web.py auto reload mode. In auto reload mode, a global instance is created every time a new page loads. If you want to avoid that, you have to use something like this:
import web
import serial
urls = ("/(.*)", "test"
)
web.config.debug = True
if(web.config.debug):
#in debug mode, make sure that global serial instance is only created at start up
if not hasattr(serObj, "_email"):
serObj = serial.Serial(0, 9600, parity=serial.PARITY_NONE)
web._serObj = serObj
else:
serObj = web._serObj
class test:
def GET(self):
return "Test"
def POST(self):
pass
if __name__ == "__main__":
app = web.application(urls, globals())
app.run()

Related

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']

Single instance of class from another module

I come from Java background and most of my thinking comes from there. Recently started learning Python. I have a case where I want to just create one connection to Redis and use it everywhere in the project. Here is how my structure and code looks.
module: state.domain_objects.py
class MyRedis():
global redis_instance
def __init__(self):
redis_instance = redis.Redis(host='localhost', port=6379, db=0)
print("Redus instance created", redis_instance)
#staticmethod
def get_instance():
return redis_instance
def save_to_redis(self, key, object_to_cache):
pickleObj = pickle.dumps(object_to_cache)
redis_instance.set(key, pickleObj)
def get_from_redis(self, key):
pickled_obj = redis_instance.get(key)
return pickle.loads(pickled_obj)
class ABC():
....
Now I want to use this from other modules.
module service.some_module.py
from state.domain_objects import MyRedis
from flask import Flask, request
#app.route('/chat/v1/', methods=['GET'])
def chat_service():
userid = request.args.get('id')
message_string = request.args.get('message')
message = Message(message_string, datetime.datetime.now())
r = MyRedis.get_instance()
user = r.get(userid)
if __name__ == '__main__':
global redis_instance
MyRedis()
app.run()
When I start the server, MyRedis() __init__ method gets called and the instance gets created which I have declared as global. Still when the service tries to access it when the service is called, it says NameError: name 'redis_instance' is not defined I am sure this is because I am trying to java-fy the approach but not sure how exactly to achieve it. I read about globals and my understanding of it is, it acts like single variable to the module and thus the way I have tried doing it. Please help me clear my confusion. Thanks!

Having the class handle pickle

I am changing some code to spin up VMs in ec2 instead of openstack. Main starts a thread per VM, and then various modules perform tasks on these VM. Each thread controls it's own VM. So, instead of either having to add parameters to all of the downstream modules to look up information, or having to change all of the code to unpickle the class instance that created the vm, I am hoping that I can have the class itself decide whether to start a new VM or return the existing pickle. That way the majority of the code wont need to be altered.
This is the general idea, and closest I have gotten to getting it to work:
import os
import sys
import pickle
if sys.version_info >= (2, 7):
from threading import current_thread
else:
from threading import currentThread as current_thread
class testA:
def __init__(self, var="Foo"):
self.class_pickle_file = "%s.p" % current_thread().ident
if os.path.isfile(self.class_pickle_file):
self.load_self()
else:
self.var = var
pickle.dump(self, open(self.class_pickle_file, "wb"))
def test_method(self):
print self.var
def load_self(self):
return pickle.load(open(self.class_pickle_file, "rb"))
x = testA("Bar")
y = testA()
y.test_method()
But that results in: NameError: global name 'var' is not defined
But, If I do y = pickle.load(open("140355004004096.p", "rb")) it works just fine. So the data IS getting in there by storing self inside the class, it's a problem of getting the class to return the pickle instead of itself...
Any ideas? Thanks.
It looks to me like you create a file named by the current thread's ident, then you instantiate another TestA object using the same thread (!!same ident!!), so it checks for a pickle file (and finds it, that's bad), then self.var never gets set.
In test_method, you check for a variable that was never set.
Run each item in its own thread to get different idents, or ensure you set self.var no matter what.

How to initialize helper method?

If I have two files helper.app and main.app, I want to be able to accomplish something like this.
helper.py
def configurestuff(dblocationstring):
# Stuff that sets name and location
generic_connection_variable = connectto(dblocationstring)
def dostuff():
# does stuff with the generic_connection_variable
In my main.py, I want to be able to do something like
import helper
helper.configure("customlocationofdb")
helper.dostuff()
#or even
helper.generic_connection_variable.someApplicableMethod()
My goal is so that I can have a main.app that is able to use the "helper" passing variables to setup a connection and reuse that variable if possible within main.app after importing the helper. What is the best way to organize my code to accomplish this? (im not sure how to access generic_connection_variable in my main.py as it is in a function, or what the best way to do this is)
Implementing this as a class allows for greater flexibility:
class Config(object):
DB_STRING = 'some default value'
ANOTHER_SETTING = 'another default'
DEBUG = True
def dostuff(self):
print 'I did stuff to ',self.DEBUG
class ProductionConfig(Config):
DEBUG = False # only turn of debugging
class DevelopmentConfig(Config):
DB_STRING = 'localhost'
def dostuff(self):
print 'Warning! Development system ',self.DEBUG
Store this in any file for example, settings.py. In your code:
from settings import Config as settings
# or from settings import ProductionConfig as settings
print settings.DEBUG # for example
You can define generic_connection_variable to be a module level variable.
So in your helper.py you will have to
generic_connection_variable = None # or whatever default you want.
def configurestuff(dblocationstring):
global generic_connection_variable
# Stuff that sets name and location
generic_connection_variable = connectto(dblocationstring)
def dostuff():
global generic_connection_variable
# does stuff with the generic_connection_variable
It's a bit hard to tell what you are asking, but have you tried making generic_connection_variable an instance variable of helper? (with the self keyword)
# helper.py:
def configurestuff(dblocationstring):
# Stuff that sets name and location
self.generic_connection_variable = connectto(dblocationstring)
Now that generic_connection_variable belongs to an instance of helper instead of being local-scoped to configurestuff, you will be able to use it in main as follows:
import helper
helper.configure("customlocationofdb")
helper.generic_connection_variable.someApplicableMethod()
But you probably need to define a class for generic_connection_variable so it has a method called someApplicableMethod().

Create functions within classes in google app engine?

I was trying to include my own functions in mainpage class, but when calling them it's not working at all, so what i did is to create a class for it and included that function in it. and in get () of mainpage class i created an instance for that class and called the function like object_name.function name() but it ain't working
class encipher:
def time_stomp():
t1=time.time()
dt = datetime.now()
dt.now()
stri=""
stri+=(str(dt.minute*dt.microsecond)[0:4])
stri+=(str(dt.second*dt.microsecond)[0:2])
stri+=(str(dt.microsecond)[0:3])
stri+=(str(dt.microsecond)[2:3])
stri+=(str(dt.microsecond)[1:2])
stri+=(str(dt.microsecond)[0:1])
return stri
#-------------------------------------------------------------
def keygen():
key_stri=""
ko=0
datalist_str1=self.time_stomp()
for i in range(6):
key_stri+=((hex(operator.xor(int(datalist_str1[ko:ko+2]),128)).replace("0x","")).zfill(2))
ko+=2
#print "Key:",key_stri
#print "Key:",key_stri
#print "Key:",key_stri
return key_stri
class MainPage(webapp.RequestHandler):
def get(self):
ddes=encipher()
global final_data_hex
global username
global filename
username = self.request.get("name")
filename=self.request.get("filename")
addr=self.request.get("mac")
path="d:/xampp/htdocs/encrypt/"+username+'/'+filename
f1 = open(path, 'r')
#f1=open(path,"r")
string=f1.read()
i=0
addr=addr.replace(":",'')
#self.response.out.write(ddes.keygen())
A python instance method needs to accept at least one parameter, self. "It's not working" is a horrible explanation of a problem; if you'd read your tracebacks you'd see an error about .keygen() accepting 0 arguments with 1 provided.
But yes, there's no reason to encapsulate methods in a class if what you really want is a function.
I figured it out. We can simply include functions out of the class and it will work perfectly.

Categories

Resources