DJANGO APP
I have interface for sending e-mail in Django:
from my_app.utils import com
com.mail.email_category1(subject, template, ...)
...
com.mail.email_category2(subject, template, ...)
I have also another interafces for ie. for SMS:
com.sms.sms_category1(template, ...)
In my_app.utils.com there are functions defined:
# my_app.utils.com
mail = CommunicationMail()
sms = CommunicationSms()
...
and categories are methods of above classes.
QUESTION
Is it possible to call new instance of CommunicationMail every time I call com.mail.email_category...? The problem is that it is the same object instance every call, so ie. when running in parallel as a task, they share properties and overlaps.
This would be the recommended structure:
from my_app.utils import com
com.Mail().email_category1(template, ...)
where my_app.utils.com is:
Mail = CommunicationMail
If you really wanted to keep the com.mail.email_category1 notation, Python would let you, of course, being the dynamic language that it is
(__getattr__ documentation):
# my_app.utils.com
class CommunicationMailFactory:
def __getattr__(self, name):
instance = CommunicationMail()
return getattr(instance, name)
mail = CommunicationMailFactory()
But use the first method! “Why,” you ask.
For one, it is makes it clear what you are doing: You are instantiating a new instance and calling a method. This is not clear with the __getattr__ hackery.
Second, you can assign the freshly instantiated instance to a variable mail1 and then call mail1.email_category1(subject, template, ...) or whatever. You have no such normal, expected flexibility with the __getattr__ hackery.
Python modules are singleton, so it will only import it once, so mail = CommunicationMail() is executed once.
you can:
from my_app.utils import com
com.CommunicationSms().sms_category1(template, ...)
Related
I am new to python and am trying to define a function and then use it in Google App Engine - but I keep getting the error "Error: global name 'cache_email_received_list' is not defined" when I try to execute the function. Any help would be greatly appreciated, thanks.
Here is my function:
class EmailMessageHandler(BaseHandler2):
def cache_email_sent_list(): #set email_sent_list to memcache
email_sent_list = db.GqlQuery("SELECT * FROM EmailMessage WHERE sender =:1 ORDER BY created DESC", user_info.username)
if email_sent_list:
string1 = "email_sent_list"
email_sent_list_cache_id = "_".join((user_info.username, string1))
memcache.set('%s' % email_sent_list_cache_id, email_sent_list, time=2000000)
logging.info('**************email_sent_list added to memcache*********')
Here is where I am trying to call it:
if email_received_list is None and email_sent_list is not None:
params = {
'email_sent_list': email_sent_list,
}
cache_email_sent_list()
cache_email_sent_list() is a method of the class EmailMessageHandler therfore the method needs to pass in self a a parameter it will therefore look like this:
class EmailMessageHandler(BaseHandler2):
def cache_email_sent_list(self): #set email_sent_list to memcache
email_sent_list = db.GqlQuery("SELECT * FROM EmailMessage WHERE sender =:1 ORDER BY created DESC", user_info.username)
if email_sent_list:
string1 = "email_sent_list"
email_sent_list_cache_id = "_".join((user_info.username, string1))
memcache.set('%s' % email_sent_list_cache_id, email_sent_list, time=2000000)
logging.info('**************email_sent_list added to memcache*********')
Then when you call it from within the class EmailMessageHandler you have to do it like this:
self.cache_email_sent_list()
If however you are calling it from outside the class EmailMessageHandler you need to first create an instance and then call it using:
instanceName.cache_email_sent_list()
Just as an addition to the previous answers: In your post you define cache_email_sent_list() as a function defined in a class definition, which will not work. I think you are confusing instance methods, static methods and functions. There's a prominent difference between these three.
So, as a stylised example:
# instance method:
class MyClass(MySuperClass):
def my_instance_method(self):
#your code here
# call the instance method:
instance = MyClass() # creates a new instance
instance.my_instance_method() # calls the method on the instance
# static method:
class MyClass(MySuperClass):
#staticmethod # use decorator to nominate a static method
def my_static_method()
#your code here
# call the static method:
MyClass.my_static_method() # calls the static method
# function
def my_function():
# your code here
# call the function:
my_function() # calls your function
Indentation is part of Python syntax and determines how the interpreter handles your code. It takes a bit getting used to but once you've got the hang of it, it's actually really handy and makes your code very readable. I think you have an indentation error in your original post. Just add the correct indentation for the method cache_email_sent_list() and call it on an instance of EmailMessageHandler and you're good to go.
The problem has nothing to do with GAE.
The problem is that you've defined cache_email_sent_list as a method of the class EmailMessageHandler, but you're trying to call it as a top-level function. You can't do that. You need to have an instance of a EmailMessageHandler to call it on.
If you're trying to call it from another method of EmailMessageHandler, that instance should be available as self. For example:
self.cache_email_sent_list()
If you're trying to call it from elsewhere, it's up to you to figure out what instance you should be calling it on. For example:
handler_passed_as_param_to_this_function.cache_email_sent_list()
Note that your error message is about cache_email_received_list, but your code only has cache_email_sent_list. I'm guessing that you have parallel code, and the exact same error for both cases, but of course I could be guessing wrong—in which case you'll have to actually show us either the code that goes with your displayed error, or the error that goes with your displayed code…
I have a mongo wrapper with hooks to a timer class, basically, every time a collection is updated or saved it spawns a timer which in turn executes a given function when it expires. My question is, what would be the pythonic way to specify those functions? My thought was to simply add them to the collection wrapper like this:
class TestCollection(Collection):
__name__ = 'test_collection'
__database__ = 'test'
__primary_key__ = 'field_1'
post_delete = 'call_this_func_with_getattr_after_delete'
expire = 'also_call_this_with_getattr_when_timer_expires'
field_1 = Key()
field_2 = Key()
field_3 = Key()
Then I can just add the logic on my timer class to run the specified function when expired and the same for my mongo wrapper. This could also be achieved in different ways (class Meta, mangled attribute names, etc...) but I just wanted to know the general consensus when doing something like this.
Don't store names you have to look up when you cab just store references to callables directly. Any function, method, or an instance of a class with a __call__ method, is an object just like anything else, and can be stored in your expired attribute.
I have an object that takes a parameter in the constructor. I was wondering how I can serve this from Pyro4. An Example:
import Pyro4
class MyPyroThing(object):
def __init__(self, theNumber):
self.Number = theNumber
Pyro4.Daemon.serveSimple(
{
MyPyroThing(): None
},
ns=True, verbose=True)
This fails of course because the constructor must have a parameter.
And when this is solved, how do you invoke such object?
theThing = Pyro4.Proxy("PYRONAME:MyPyroThing")
EDIT:
I think this question was not written correctly, see my answer below.
The answers above where not what I was really asking, meaning I explained my question badly. Mea Culpa.
I wanted to invoke an instance on the client. But that is not how Pyro4 works at all. A class in instantiated on the server and this instance is transmitted over the wire.
After mailing Irmin (the original developer) it came clear to me how Pyro4 works.
So, what I do now is use a factory pattern where I ask the factory to give me an instance of an object. For instance:
psf = Pyro4.Proxy("PYRONAME:MyApp.Factories.ProductFactory")
product = psf.GetProductOnButton(buttonNoPressed, parentProductId)
product is an instance of the Product() class. Because the instance is registered in the Pyro daemon, i can call methods on this instance of Product() too. Look at the shoppingcart example to know where I got my eureka moment.
Instead of using Pyro4.Daemon.serveSimple you can:
Get the name server using Pyro4.locateNS
Create a Pyro4.Daemon object
Create the objects you need to expose
Use the daemon register method to make them available
Use the name server register method to provide a name to uri mapping
Start the daemon loop
The code would be more or less as follows:
import Pyro4
name_server = Pyro4.locateNS()
daemon = Pyro4.Daemon()
my_object = MyPyroThing(parameter)
my_object_uri = daemon.register(my_object)
name_server.register('MyPyroThing', my_object_uri)
daemon.requestLoop()
After this, my_object URI will be available in the name server as MyPyroThing.
I am working in Python with an Email() class that I would like to extend into a SerializeEmail() class, which simply adds two further methods, .write_email() and .read_email(). I would like this sort of behaviour:
# define email
my_email = SerializeEmail()
my_email.recipients = 'link#hyrule.com'
my_email.subject = 'RE: Master sword'
my_email.body = "Master using it and you can have this."
# write email to file system for hand inspection
my_email.write_email('my_email.txt')
...
# Another script reads in email
my_verified_email = SerializeEmail()
my_verified_email.read_email('my_email.txt')
my_verified_email.send()
I have navigated the json encode/decode process, and I can successfully write my SerializeEmail() object, and read it in, however, I can't find a satisfactory way to recreate my object via a SerializeEmail.read_email() call.
class SerializeEmail(Email):
def write_email(self,file_name):
with open(file_name,"w") as f:
json.dump(self,f,cls=SerializeEmailJSONEncoder,sort_keys=True,indent=4)
def read_email(self,file_name):
with open(file_name,"r") as f:
json.load(f,cls=SerializeEmailJSONDecoder)
The problem here is that the json.load() call in my read_email() method returns an instance of my SerializeEmail object, but doesn't assign that object to the current instance that I'm using to call it. So right now I'd have to do something like this,
another_email = my_verified_email.read_email('my_email.txt')
when what I want is for the call to my_veridied_email.read_email() to populate the current instance of my_verified_email with the data on the file. I've tried
self = json.load(f,cls=SerializeEmailJSONDecoder)
but that doesn't work. I could just assign each individual element of my returned object to my "self" object, but that seems ad-hoc and inelegant, and I'm looking for the "right way" to do this, if it exists. Any suggestions? If you think that my whole approach is flawed and recommend a different way of accomplishing this task, please sketch it out for me.
While you could jump through a number of hoops to load serialized content into an existing instance, I wouldn't recommend doing so. It's an unnecessary complication which really gains you nothing; it means that the extra step of creating a dummy instance is required every time you want to load an e-mail from JSON. I'd recommend using either a factory class or a factory method which loads the e-mail from the serialized JSON and returns it as a new instance. My personal preference would be a factory method, which you'd accomplish as follows:
class SerializeEmail(Email):
def write_email(self,file_name):
with open(file_name,"w") as f:
json.dump(self,f,cls=SerializeEmailJSONEncoder,sort_keys=True,indent=4)
#staticmethod
def read_email(file_name):
with open(file_name,"r") as f:
return json.load(f,cls=SerializeEmailJSONDecoder)
# You can now create a new instance by simply doing the following:
new_email = SerializeEmail.read_email('my_email.txt')
Note the #staticmethod decorator, which allows you to call the method on the class without any implicit first argument being passed in. Normally factory methods would be #classmethods, but since you're loading the object from JSON, the implicit class argument is unnecessary.
Notice how, with this modification, you don't need to instantiate a SerializeEmail object before you can load another one from JSON. You simply call the method directly on the class and get the desired behavior.
I have a python fuse project based on the Xmp example in the fuse documentation. I have included a small piece of the code to show how this works. For some reason get_file does get called and the class gets created, but instead of fuse calling .read() on the class from get_file (file_class) fuse keeps calling Dstorage.read() which defeats the purpose in moving the read function out of that class.
class Dstorage(Fuse, Distributor):
def get_file(self, server, path, flags, *mode):
pass
# This does some work and passes back an instance of
# a class very similar to XmpFile
def main(self, *a, **kw):
self.file_class = self.get_file
return Fuse.main(self, *a, **kw)
I have my code hosted on launchpad, you can download it with this command.
bzr co https://code.launchpad.net/~asa-ayers/+junk/dstorage
bzr branch lp:~asa-ayers/dstorage/trunk
solution:
I used a proxy class that subclasses the one I needed and in the constructor I get the instance of the class I need and overwrite all of the proxy's methods to simply call the instance methods.
Looking at the code of the Fuse class (which is a maze of twisty little passages creating method proxies), I see this bit (which is a closure used to create a setter inside Fuse.MethodProxy._add_class_type, line 865):
def setter(self, xcls):
setattr(self, type + '_class', xcls)
for m in inits:
self.mdic[m] = xcls
for m in proxied:
if hasattr(xcls, m):
self.mdic[m] = self.proxyclass(m)
When you do self.file_class = self.get_file, this gets called with self.get_file, which is a bound method. The loop over proxied attributes is expecting to be able to get the attributes off the class you set, to put them into its mdic proxy dictionary after wrapping them, but they aren't there, because it's a bound method, rather than a class. Since it can't find them, it reverts to calling them on Dstorage.
So, long story short, you can't use a callable that returns an instance (kind of a pseudo-class) instead of a class here, because Fuse is introspecting the object that you set to find the methods it should call.
You need to assign a class to file_class - if you need to refer back to the parent instance, you can use the nested class trick they show in the docs.