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.
Related
I am a beginner in Python, so please be... kind?
Anyway, I need use a static method to call another method, which requires the use of "self" (and thus, a normal method I believe). I am working with Telethon, a Python implementation of Telegram. I have tried other questions on SO, but I just can't seem to find a solution to my problem.
An overview of the program (please correct me if I'm wrong):
1) interactive_telegram_client is a child class of telegram_client, and it creates an instance.
#interactive_telegram_client.py
class InteractiveTelegramClient(TelegramClient):
super().__init__(session_user_id, api_id, api_hash, proxy)
2) When the InteractiveTelegramClient runs, it adds an update_handler self.add_update_handler(self.update_handler) to constantly check for messages received/sent, and prints it to screen
#telegram_client.py
def add_update_handler(self, handler):
"""Adds an update handler (a function which takes a TLObject,
an update, as its parameter) and listens for updates"""
if not self.sender:
raise RuntimeError(
"You should connect at least once to add update handlers.")
self.sender.add_update_handler(handler)
#interactive_telegram_client.py
#staticmethod
def update_handler(update_object):
try:
if type(update_object) is UpdateShortMessage:
if update_object.out:
print('You sent {} to user #{}'.format(update_object.message,
update_object.user_id))
else:
print('[User #{} sent {}]'.format(update_object.user_id,
update_object.message))
Now, my aim here is to send back an auto-reply message upon receiving a message. Thus, I think that adding a call to method InteractiveTelegramClient.send_ack(update_object) in the update_handler method would serve my needs.
#interactive_telegram_client.py
def send_ack(self, update_object):
entity = update_object.user_id
message = update_object.message
msg, entities = parse_message_entities(message)
msg_id = utils.generate_random_long()
self.invoke(SendMessageRequest(peer=get_input_peer(entity),
message=msg,random_id=msg_id,entities=entities,no_webpage=False))
However, as you can see, I require the self to invoke this function (based on the readme, where I assume client to refer to the same thing as self). Since the method update_handler is a static one, self is not passed through, and as such I cannot invoke the call as such.
My possible strategies which have failed include:
1) Instantiating a new client for the auto-reply
- Creating a new client/conversation for each reply...
2) Making all the methods non-static
- Involves a tremendous amount of work since other methods modified as well
3) Observer pattern (sounds like a good idea, I tried, but due to a lack of skills, not succeeded)
I was wondering if there's any other way to tackle this problem? Or perhaps it's actually easy, just that I have some misconception somewhere?
Forgot to mention that due to some restrictions on my project, I can only use Telethon, as opposed to looking at other alternatives. Adopting another library (like an existing auto-reply one) is allowed, though I did not really look into that since merging that and Telethon may be too difficult for me...
based on the readme, where I assume client to refer to the same thing as self
Correct, since the InteractiveTelegramClient subclasses the TelegramClient and hence, self is an instance of the extended client.
Instantiating a new client for the auto-reply - Creating a new client/conversation for each reply
This would require you to create another authorization and send another code request to login, because you can't work with the same *.session at the same time.
Making all the methods non-static - Involves a tremendous amount of work since other methods modified as well
It doesn't require such amount of work. Consider the following example:
class Example:
def __init__(self, a):
self.a = a
def do_something(self):
Example.other_method()
#staticmethod
def other_method():
print('hello, world!')
Is equivalent to:
class Example:
def __init__(self, a):
self.a = a
def do_something(self):
self.other_method()
#staticmethod
def other_method():
print('hello, world!')
It doesn't matter whether you use self. or the class name to refer to a static method from within the class. Since the InteractiveClientExample already uses self., all you would have to do would be changing:
#staticmethod
def update_handler(update_object):
for
def update_handler(self, update_object):
For more on the #staticmethod decorator, you can refer to the docs.
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, ...)
I am trying make a pyro4 proxy indexable. To test this, I took the greeting example from http://pythonhosted.org/Pyro4/intro.html#simple-example and I modified it:
Server:
import Pyro4
class Test(object):
def __getitem__(self, index):
return index
test = Test()
print test[1]
print test[100]
daemon = Pyro4.Daemon()
uri = daemon.register(test)
print("Ready. Object uri =", uri)
daemon.requestLoop()
Client:
import Pyro4
uri = input("What is the Pyro uri of the object? ").strip()
test = Pyro4.Proxy(uri)
print test.__getitem__(1)
print test.__getitem__(100)
print test[1]
print test[100]
The [] notation works on the server, but not also on the client proxy. I get:
TypeError: 'Proxy' object does not support indexing
But calls directly to __getitem__ do work.
I've just run into this myself.
From what I can see looking at the source code, Pyro4 doesn't proxy the Python implicit __getitem__ call that index notation uses. It does proxy __getattr__, which is why calling the __getitem__ method directly works.
What you can do, though, is create (on the client side) a proxy to the Pyro proxy(!) that implements __getitem__ and lets all other method calls fall through:
class TestProxy(object):
def __init__(self, pyroTest):
self.pyroTest = pyroTest
def __getattr__(self, name):
return getattr(self.pyroTest, name)
def __getitem__(self, item):
return self.pyroTest.__getitem__(item)
Then you can use index notation on the TestProxy object, as well as call methods in the normal Pyro way.
(Disclaimer: there are probably all sorts of Pythonic edge cases that this simple solution fails to cover!)
This might be worth an enhancement request for Pyro.
While this could perhaps be added to the Pyro proxy, it actually promotes potentially horrible performing code.
Indexing an object usually is done because the object is a collection of some sort and you are probably iterating over it. Doing this on a Pyro proxy will result in terrible performance because every index lookup will be a remote call.
It is usually a lot faster and way more efficient to simply get the collection you want to iterate over all at once using one remote call, and then iterate over the resulting local object as usual.
YMMV, it depends on the situation ofcourse.
I am following this explanation, and I don't quite get how Python interpreter arrives at the following. In the first example, is Python seeing #implementer(IAmericanSocket) is not implemented by UKSocket, then it decides to make it a AdaptToAmericanSocket because that is the only implementation of IAmericanSocket with one argument? What if there is another class instance implementing IAmericanSocket with one argument? In the second example, why is IAmericanSocket not overriding AmericanSocket's voltage method?
>>> IAmericanSocket(uk)
<__main__.AdaptToAmericanSocket instance at 0x1a5120>
>>> IAmericanSocket(am)
<__main__.AmericanSocket instance at 0x36bff0>
with the code below:
from zope.interface import Interface, implementer
from twisted.python import components
class IAmericanSocket(Interface):
def voltage():
"""
Return the voltage produced by this socket object, as an integer.
"""
#implementer(IAmericanSocket)
class AmericanSocket:
def voltage(self):
return 120
class UKSocket:
def voltage(self):
return 240
#implementer(IAmericanSocket)
class AdaptToAmericanSocket:
def __init__(self, original):
self.original = original
def voltage(self):
return self.original.voltage() / 2
components.registerAdapter(
AdaptToAmericanSocket,
UKSocket,
IAmericanSocket)
You can see the full documentation for zope.interface here: http://docs.zope.org/zope.interface/ - it may provide a more thorough introduction than Twisted's quick tutorial.
To answer your specific question, the registerAdapter call at the end there changes the behavior of calling IAmericanSocket.
When you call an Interface, it first checks to see if its argument provides itself. Since the class AmericanSocket implements IAmericanSocket, instances of AmericanSocket provide IAmericanSocket. This means that when you call IAmercianSocket with an argument of an AmericanSocket instance, you just get the instance back.
However, when the argument does not provide the interface already, the interface then searches for adapters which can convert something that the argument does provide to the target interface. ("Searches for adapters" is a huge oversimplification, but Twisted's registerAdapter exists specifically to allow for this type of simplification.)
So when IAmericanSocket is called with an instance of a UKSocket, it finds a registered adapter from instances of UKSocket. The adapter itself is a 1-argument callable that takes an argument of the type being adapted "from" (UKSocket) and returns a value of the type being adapted "to" (provider of IAmericanSocket). AdaptToAmericanSocket is a class, but classes are themselves callable, and since its constructor takes a UKSocket, it fits the contract of thing-that-takes-1-argument-of-type-UKSocket-and-returns-an-IAmericanSocket.
The existence of another class would not make a difference, unless it were registered as an adapter. If you register two adapters which might both be suitable their interactions are complicated, but since they both do the job, in theory you shouldn't care which one gets used.
I'm trying to understand how to make RPC calls using Python. I have a stupid server that defines a class and exposes a method that create instances of that class:
# server.py
class Greeter(object):
def __init__(self, name):
self.name = name
def greet(self):
return "Hi {}!".format(self.name)
def greeter_factory(name):
return Greeter(name)
some_RPC_framework.register(greeter_factory)
and a client that wants to get an instance of the Greeter:
# client.py
greeter_factory = some_RPC_framework.proxy(uri_given_by_server)
h = greeter_factory("Heisemberg")
print("Server returned:", h.greet())
The problem is that I've found no framework that allows to return instances of user-defined objects, or that only returns a dict with the attributes of the object (for example, Pyro4).
In the past I've used Java RMI, where you can specify a codebase on the server where the client can download the compiled classes, if it needs to. Is there something like this for Python? Maybe some framework that can serialize objects along with the class bytecode to let the client have a full-working instance of the class?
Pyro can do this to a certain extent. You can register custom class (de)serializers when using the default serializer. Or you can decide to use the pickle serializer, but that has severe security implications. See http://pythonhosted.org/Pyro4/clientcode.html#serialization
What Pyro won't do for you, even when using the pickle serializer, is transfer the actual bytecode that makes up the module definition. The client, in your case, has to be able to import the module defining your classes in the regular way. There's no code transportation.
You can consider using
payload = CPickle.dump(Greeter(name))
on server side and on client side once the payload is received do -
h = CPickle.load(payload)
to get the instance of Greeter object that server has created.