### Basic Pyro Daemon Setup and Object Publishing Source: https://github.com/irmen/pyro5/blob/master/docs/source/servercode.rst This is the fundamental setup for a Pyro server. It involves defining an exposed class, creating a Pyro daemon, registering the class with the daemon, and starting the daemon's request loop to listen for incoming client connections. ```python import Pyro5.server @Pyro5.server.expose class MyPyroThing(object): # ... methods that can be called go here... pass daemon = Pyro5.server.Daemon() uri = daemon.register(MyPyroThing) print(uri) daemon.requestLoop() ``` -------------------------------- ### Start Pyro Test Echo Server Source: https://github.com/irmen/pyro5/blob/master/examples/http/Readme.txt Command to start the Pyro test echo server, required for some client examples. ```bash pyro5-echoserver -n or python -m Pyro5.utils.echoserver -n ``` -------------------------------- ### Start Pyro5 Echo Server Source: https://github.com/irmen/pyro5/blob/master/examples/echoserver/Readme.txt Use this command to start the built-in echo server for testing Pyro5 applications. ```bash $ python -m Pyro5.utils.echoserver ``` ```bash $ pyro5-echoserver ``` -------------------------------- ### Start Pyro Name Server Command Line Source: https://github.com/irmen/pyro5/blob/master/docs/source/nameserver.rst Starts the Pyro Name Server using the command line tool. Options can control hostname, port, and Unix domain socket binding. The server prints its broadcast and NS addresses upon startup. ```bash $ pyro5-ns -n neptune Broadcast server running on 0.0.0.0:9091 NS running on neptune:9090 (192.168.178.20) URI = PYRO:Pyro.NameServer@neptune:9090 ``` -------------------------------- ### Pyro Client Connection Example Source: https://github.com/irmen/pyro5/blob/master/docs/source/servercode.rst Example of a Pyro client connecting to a published object using its URI and calling a method. ```python import Pyro5.client # use the URI that the server printed: uri = "PYRO:obj_b2459c80671b4d76ac78839ea2b0fb1f@localhost:49383" thing = Pyro5.client.Proxy(uri) print(thing.method(42)) # prints 84 ``` -------------------------------- ### Start Pyro HTTP Gateway Server Source: https://github.com/irmen/pyro5/blob/master/docs/source/tipstricks.rst Launch the HTTP gateway server from the command line. Use the help option to see available configurations. ```bash python -m Pyro5.utils.httpgateway [options] ``` ```bash pyro5-httpgateway [options] ``` -------------------------------- ### Pyro5.server.serve() Source: https://github.com/irmen/pyro5/blob/master/docs/source/servercode.rst Publish a dictionary of objects or classes and start Pyro's request loop using a single statement. ```APIDOC ## Pyro5.server.serve() ### Description A convenient method to publish a dictionary of objects/classes and start Pyro's request loop. It handles daemon creation and object registration automatically. ### Method Signature ```python Pyro5.server.serve(objects, host=None, port=0, daemon=None, use_ns=True, verbose=True) ``` ### Parameters #### `objects` (dict) - **Required** - A mapping of objects or classes to their names. These are the Pyro objects that will be hosted by the daemon. #### `host` (str or None) - **Optional** - The hostname where the daemon should be reached. #### `port` (int) - **Optional** - The port number where the daemon should be accessible. #### `daemon` (Pyro5.server.Daemon) - **Optional** - An existing daemon instance to use. If not provided, a new daemon will be created. #### `use_ns` (bool) - **Optional** - If `True` (default), objects are registered in the name server. If `False`, objects are only hosted by the daemon and not published in a name server. #### `verbose` (bool) - **Optional** - If `True` (default), prints information about registered objects. ### Request Example ```python import Pyro5.server @Pyro5.server.expose class MyPyroThing(object): pass obj = MyPyroThing() Pyro5.server.serve({ MyPyroThing: None, # register the class obj: None # register one specific instance }, ns=False) ``` ### Notes - If `use_ns` is `True`, providing logical names for objects is recommended. If a name is `None`, the object is available in the daemon but not registered in the name server. - If `use_ns` is `False`, provided names are used as object names within the daemon. A `None` name results in an auto-generated internal name. - Names provided in the `objects` dictionary must be unique or `None`. - If `None` is used for a name, `verbose` should also be `True` to know the generated name. - If a `daemon` is not provided, `serve` creates a new one using default or specified `host` and `port`. ``` -------------------------------- ### Start Pyro5 Echo Server Source: https://github.com/irmen/pyro5/blob/master/examples/maxsize/Readme.txt Start the Pyro5 echo server to test message handling. This server will listen for incoming Pyro connections. ```shell python -m Pyro5.utils.echoserver ``` ```shell pyro5-echoserver ``` -------------------------------- ### Start Pyro HTTP Gateway Source: https://github.com/irmen/pyro5/blob/master/examples/http/Readme.txt Command to start the Pyro HTTP gateway. Use the '-e' option to expose specific Pyro objects. ```bash python -m Pyro5.utils.httpgateway -e 'Pyro.|test.' or: pyro5-httpgateway -e 'Pyro.|test.' ``` -------------------------------- ### Pyro Daemon with Name Server Integration Source: https://github.com/irmen/pyro5/blob/master/docs/source/servercode.rst This example demonstrates setting up a Pyro daemon and registering an object with the name server for easier lookup. It includes both the normal code flow and the alternative using `serve`. ```python import Pyro5.server import Pyro5.core @Pyro5.server.expose class Thing(object): def method(self, arg): return arg*2 # ------ normal code ------ daemon = Pyro5.server.Daemon(host="yourhostname") ns = Pyro5.core.locate_ns() uri = daemon.register(Thing) ns.register("mythingy", uri) daemon.requestLoop() # ------ alternatively, using serve ----- Pyro5.server.serve( { Thing: "mythingy" }, ns=True, verbose=True, host="yourhostname") ``` -------------------------------- ### Installing Pyro Exception Hook Source: https://github.com/irmen/pyro5/blob/master/docs/source/errors.rst Install Pyro5.errors.excepthook into sys.excepthook to automatically print complete Pyro tracebacks, including remote ones. ```python import sys import Pyro5.errors sys.excepthook = Pyro5.errors.excepthook ``` -------------------------------- ### Python Client for Pyro HTTP Gateway Source: https://github.com/irmen/pyro5/blob/master/examples/http/Readme.txt Example Python client code for interacting with the Pyro HTTP gateway. Ensure Pyro5 is installed. ```python # client.py: python (3.x) client code # Example usage: # from Pyro5.client import HTTPClient # # # Adjust URL if gateway is elsewhere # client = HTTPClient('http://localhost:8000') # # try: # # Replace 'echoserver.test' with the actual object name and 'hello' with the method name # result = client.request('echoserver.test', 'hello', ['World']) # print(f"Result from echoserver: {result}") # except Exception as e: # print(f"Error calling echoserver: {e}") ``` -------------------------------- ### Get Pyro Configuration as Dictionary Source: https://github.com/irmen/pyro5/blob/master/docs/source/config.rst Retrieve all current Pyro configuration settings as a Python dictionary. ```python Pyro5.config.as_dict() ``` -------------------------------- ### Simple Batched Calls Example Source: https://github.com/irmen/pyro5/blob/master/docs/source/clientcode.rst Demonstrates how to group multiple method calls on the same proxy object into a single 'batched call' to reduce latency and overhead. The results are obtained as a generator. ```python batch = Pyro5.api.BatchProxy(proxy) batch.method1() batch.method2() # more calls ... batch.methodN() results = batch() # execute the batch for result in results: print(result) # process result in order of calls... ``` -------------------------------- ### Example output of Pyro5 nsc list Source: https://github.com/irmen/pyro5/blob/master/docs/source/tutorials.rst This output shows the name server itself registered as 'Pyro.NameServer' and its associated URI. It also includes metadata about the registered class. ```text --------START LIST Pyro.NameServer --> PYRO:Pyro.NameServer@localhost:9090 metadata: {'class:Pyro5.nameserver.NameServer'} --------END LIST ``` -------------------------------- ### Basic Pyro Daemon and Object Exposure Source: https://github.com/irmen/pyro5/blob/master/docs/source/servercode.rst This snippet shows the fundamental steps to create a Pyro daemon, expose a class as a Pyro object, and start the request loop. It also demonstrates an alternative using the `serve` function. ```python import Pyro5.server @Pyro5.server.expose class Thing(object): def method(self, arg): return arg*2 # ------ normal code ------ daemon = Pyro5.server.Daemon() uri = daemon.register(Thing) print("uri=",uri) daemon.requestLoop() # ------ alternatively, using serve ----- Pyro5.server.serve( { Thing: None }, ns=False, verbose=True) ``` -------------------------------- ### Get Pyro Configuration as String Dump Source: https://github.com/irmen/pyro5/blob/master/docs/source/config.rst Obtain a formatted string representation of the current Pyro configuration, suitable for display. ```python Pyro5.config.dump() ``` -------------------------------- ### Publishing Objects with Pyro5.server.serve() Source: https://github.com/irmen/pyro5/blob/master/docs/source/servercode.rst Publish a dictionary of objects or classes and start Pyro's request loop using the serve() function. This can optionally register objects in the name server. ```python import Pyro5.server @Pyro5.server.expose class MyPyroThing(object): pass obj = MyPyroThing() Pyro5.server.serve( { MyPyroThing: None, # register the class obj: None # register one specific instance }, ns=False) ``` -------------------------------- ### Get Metadata with List Source: https://github.com/irmen/pyro5/blob/master/docs/source/nameserver.rst Set `return_metadata=True` in the `list` method to retrieve metadata for all registered objects. ```python ns.list(return_metadata=True) # returns something like: # {'printer.secondfloor': ('PYRO:printer1@host:1234', {'printer'}), # 'Pyro.NameServer': ('PYRO:Pyro.NameServer@localhost:9090', {'class:Pyro5.nameserver.NameServer'})} ``` -------------------------------- ### Accessing Daemon Object from Name Server Source: https://github.com/irmen/pyro5/blob/master/docs/source/servercode.rst This example demonstrates how to access the daemon object from a running name server using Pyro client code. It shows the usage of Pyro5.client and the reserved object name 'Pyro.Daemon'. ```python >>> import Pyro5.client >>> daemon_proxy = Pyro5.client.Proxy("Pyro.Daemon") >>> print(daemon_proxy.ping()) True ``` -------------------------------- ### Get Metadata with Lookup Source: https://github.com/irmen/pyro5/blob/master/docs/source/nameserver.rst Set `return_metadata=True` in the `lookup` method to retrieve the associated metadata tags along with the URI. ```python ns.lookup("printer.secondfloor", return_metadata=True) # returns: (, {'printer'}) ``` -------------------------------- ### Pyro Client using Name Server Lookup Source: https://github.com/irmen/pyro5/blob/master/docs/source/servercode.rst Example of a Pyro client connecting to an object published via the name server using its registered name. ```python import Pyro5.client thing = Pyro5.client.Proxy("PYRONAME:mythingy") print(thing.method(42)) # prints 84 ``` -------------------------------- ### Expose methods and properties with @Pyro5.server.expose Source: https://github.com/irmen/pyro5/blob/master/docs/source/servercode.rst Use the @Pyro5.server.expose decorator to make methods, properties, and entire classes available for remote access. Private members (starting with an underscore) are not exposed by default, except for certain dunder methods. ```python import Pyro5.server class PyroService(object): value = 42 # not exposed def __dunder__(self): pass def _private(self): pass def __private(self): pass @Pyro5.server.expose def get_value(self): return self.value @Pyro5.server.expose @property def attr(self): return self.value @Pyro5.server.expose @attr.setter def attr(self, value): self.value = value ``` -------------------------------- ### Creating a Pyro Daemon Source: https://github.com/irmen/pyro5/blob/master/docs/source/servercode.rst Demonstrates how to create a Pyro daemon, optionally providing a custom configuration. ```APIDOC ## Daemon([host=None, port=0, unixsocket=None, nathost=None, natport=None, interface=DaemonObject, connected_socket=None]) ### Description Create a new Pyro daemon. ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Parameters - **host** (str or None) - the hostname or IP address to bind the server on. Default is ``None`` which means it uses the configured default (which is localhost). It is necessary to set this argument to a visible hostname or ip address, if you want to access the daemon from other machines. When binding to a hostname be careful of your OS's policies as it might still bind to localhost as well. Depending on your DNS setup you may have to use "", "0.0.0.0" or an explicit externally visible IP addres to make the server accessible over the network. - **port** (int) - port to bind the server on. Defaults to 0, which means to pick a random port. - **unixsocket** (str or None) - the name of a Unix domain socket to use instead of a TCP/IP socket. Default is ``None`` (don't use). - **nathost** (str or None) - hostname to use in published addresses (useful when running behind a NAT firewall/router). Default is ``None`` which means to just use the normal host. For more details about NAT, see :ref:`nat-router`. - **natport** (int) - port to use in published addresses (useful when running behind a NAT firewall/router). If you use 0 here, Pyro will replace the NAT-port by the internal port number to facilitate one-to-one NAT port mappings. - **interface** (Pyro5.server.DaemonObject) - optional alternative daemon object implementation (that provides the Pyro API of the daemon itself) - **connected_socket** (socket) - optional existing socket connection to use instead of creating a new server socket ### Request Example ```python custom_daemon = Pyro5.server.Daemon(host="example", nathost="example") # some additional custom configuration Pyro5.server.serve( { MyPyroThing: None }, daemon = custom_daemon) ``` ### Response #### Success Response (200) None #### Response Example None ``` -------------------------------- ### Serve with Custom Daemon Source: https://github.com/irmen/pyro5/blob/master/docs/source/servercode.rst Provide a pre-configured daemon instance to the serve function. This allows for custom host, port, or NAT settings. ```python custom_daemon = Pyro5.server.Daemon(host="example", nathost="example") # some additional custom configuration Pyro5.server.serve( { MyPyroThing: None }, daemon = custom_daemon) ``` -------------------------------- ### Pyro5.server.Daemon Context Manager Source: https://github.com/irmen/pyro5/blob/master/docs/source/servercode.rst Demonstrates how to use the Pyro5.server.Daemon as a context manager to ensure resources are properly freed when the request loop terminates. ```APIDOC ## Pyro5.server.Daemon Context Manager ### Description Use the `Daemon` as a context manager to nicely free its resources when the request loop terminates. ### Usage ```python import Pyro5.server with Pyro5.server.Daemon() as daemon: daemon.register(...) daemon.requestLoop() ``` ``` -------------------------------- ### Catching Remote Exceptions Source: https://github.com/irmen/pyro5/blob/master/docs/source/errors.rst Catch remote exceptions as if they occurred locally. This example shows how to catch a ZeroDivisionError raised by a remote object. ```python import Pyro5.api divider=Pyro5.api.Proxy( ... ) try: result = divider.div(999,0) except ZeroDivisionError: print("yup, it crashed") ``` -------------------------------- ### PYROMETA URI Protocol Lookup Source: https://github.com/irmen/pyro5/blob/master/docs/source/nameserver.rst Use the `PYROMETA` URI protocol to perform a `meta_all` lookup and get a proxy to a matching object. ```python Pyro5.client.Proxy("PYROMETA:resource.printer,performance.fast") ``` -------------------------------- ### Get Non-NAT URI from Pyro Daemon Source: https://github.com/irmen/pyro5/blob/master/docs/source/tipstricks.rst Retrieve a URI that does not include NAT information from a Pyro daemon by setting nat=False in the uriFor method. ```python # d = Pyro5.api.Daemon(...) print(d.uriFor("thing")) # "PYRO:thing@pyro.server.com:5555" print(d.uriFor("thing", nat=False)) # "PYRO:thing@localhost:36124" uri2 = d.uriFor(uri.object, nat=False) # get non-natted uri ``` -------------------------------- ### List Name Server Entries Source: https://github.com/irmen/pyro5/blob/master/docs/source/nameserver.rst Lists entries in the name server, optionally filtering by a prefix. Metadata associated with entries is also displayed. ```bash $ pyro5-nsc list Pyro --------START LIST - prefix 'Pyro' Pyro.NameServer --> PYRO:Pyro.NameServer@localhost:9090 metadata: {'class:Pyro5.nameserver.NameServer'} --------END LIST - prefix 'Pyro' ``` -------------------------------- ### Retrieving metadata with list Source: https://github.com/irmen/pyro5/blob/master/docs/source/nameserver.rst Demonstrates how to list all registered objects and retrieve their URIs and metadata tags. ```APIDOC ## Retrieving Metadata with List ### Description List all registered objects in the name server and optionally retrieve their associated metadata tags. ### Method `Pyro5.nameserver.NameServer.list(return_metadata=False)` ### Parameters - **return_metadata** (boolean, optional) - If True, return a dictionary where values are tuples of (URI, metadata_set). Defaults to False. ### Request Example ```python registered_objects = ns.list(return_metadata=True) # returns something like: # {'printer.secondfloor': ('PYRO:printer1@host:1234', {'printer'}), # 'Pyro.NameServer': ('PYRO:Pyro.NameServer@localhost:9090', {'class:Pyro5.nameserver.NameServer'})} ``` ``` -------------------------------- ### JavaScript Client for Pyro HTTP Gateway Source: https://github.com/irmen/pyro5/blob/master/examples/http/Readme.txt Example JavaScript client code for interacting with the Pyro HTTP gateway. This code is intended for Node.js environments. ```javascript // client.js: javascript client code, for node.js // Example usage: // const pyro = require('pyro5-http-client'); // const client = new pyro.HTTPClient('http://localhost:8000'); // Adjust URL if gateway is elsewhere // async function callEcho() { // try { // const result = await client.request('echoserver.test', 'hello', ['World']); // console.log('Result from echoserver:', result); // } catch (error) { // console.error('Error calling echoserver:', error); // } // } // callEcho(); ``` -------------------------------- ### Using Daemon as a Context Manager Source: https://github.com/irmen/pyro5/blob/master/docs/source/servercode.rst Use the Pyro5.server.Daemon as a context manager to ensure resources are nicely freed when the request loop terminates. ```python with Pyro5.server.Daemon() as daemon: daemon.register(...) daemon.requestLoop() ``` -------------------------------- ### Get Client Wire Protocol Version in Python Source: https://github.com/irmen/pyro5/blob/master/docs/source/tipstricks.rst Determine the wire protocol version used by your client code by accessing the PROTOCOL_VERSION constant from Pyro5.protocol. ```python import Pyro5.protocol as p print(p.PROTOCOL_VERSION) ``` -------------------------------- ### Set Pyro Configuration Items in Code Source: https://github.com/irmen/pyro5/blob/master/docs/source/config.rst Modify Pyro's configuration by directly setting attributes on the Pyro5.config object. This is typically done at the start of your program. ```python Pyro5.config.COMPRESSION = True Pyro5.config.SERVERTYPE = "multiplex" ``` -------------------------------- ### Pyro5 Greeting Client (No Name Server) Source: https://github.com/irmen/pyro5/blob/master/docs/source/intro.rst This is the client-side code to connect to the Pyro greeting server. It prompts for the server's URI and the user's name, then calls the remote method. Save this as greeting-client.py. ```python import Pyro5.api uri = input("What is the Pyro uri of the greeting object? ").strip() name = input("What is your name? ").strip() greeting_maker = Pyro5.api.Proxy(uri) # get a Pyro proxy to the greeting object print(greeting_maker.get_fortune(name)) # call method normally ``` -------------------------------- ### Set Pyro Configuration via Environment Variables (Windows) Source: https://github.com/irmen/pyro5/blob/master/docs/source/config.rst Configure Pyro by setting environment variables before running your program. Use the PYRO_ prefix for configuration items. ```batch C:\> set PYRO_COMPRESSION=true C:\> set PYRO_SERVERTYPE=multiplex ``` -------------------------------- ### Set Pyro Configuration via Environment Variables (Linux/macOS) Source: https://github.com/irmen/pyro5/blob/master/docs/source/config.rst Configure Pyro by setting environment variables before running your program. Use the PYRO_ prefix for configuration items. ```bash $ export PYRO_COMPRESSION=true $ export PYRO_SERVERTYPE=multiplex ``` -------------------------------- ### Registering an object with metadata Source: https://github.com/irmen/pyro5/blob/master/docs/source/nameserver.rst Demonstrates how to register an object with associated metadata tags using the `register` method. ```APIDOC ## Registering with Metadata ### Description Register an object with the name server and associate a set of metadata tags with it. ### Method `Pyro5.nameserver.NameServer.register(name, uri, metadata=None, metadata_any=None, metadata_all=None)` ### Parameters - **name** (string) - The name of the object to register. - **uri** (string) - The Pyro URI of the object. - **metadata** (set of strings, optional) - A set of strings representing the metadata tags for this object. ### Request Example ```python ns.register("printer.secondfloor", "PYRO:printer1@host:1234", metadata={"printer"}) ``` ``` -------------------------------- ### Remote TypeError Traceback Example Source: https://github.com/irmen/pyro5/blob/master/docs/source/errors.rst This is a remote traceback from Pyro5 showing a TypeError. It details the exception, the remote call stack, and the local values at the point of error, specifically highlighting an attempt to divide a string by an integer. ```text +--- This exception occurred remotely (Pyro) - Remote traceback: ---------------------------------------------------- EXCEPTION : unsupported operand type(s) for //: 'str' and 'int' Extended stacktrace follows (most recent call last) ---------------------------------------------------- File "/home/irmen/Projects/pyro5/Pyro5/server.py", line 466, in Daemon.handleRequest Source code: data = method(*vargs, **kwargs) # this is the actual method call to the Pyro object ---------------------------------------------------- File "/home/irmen/Projects/pyro5/examples/exceptions/excep.py", line 24, in TestClass.complexerror Source code: x.crash() Local values: self = x = ---------------------------------------------------- File "/home/irmen/Projects/pyro5/examples/exceptions/excep.py", line 32, in Foo.crash Source code: self.crash2('going down...') Local values: self = ---------------------------------------------------- File "/home/irmen/Projects/pyro5/examples/exceptions/excep.py", line 36, in Foo.crash2 Source code: x = arg // 2 Local values: arg = 'going down...' self = ---------------------------------------------------- EXCEPTION : unsupported operand type(s) for //: 'str' and 'int' ---------------------------------------------------- +--- End of remote traceback ``` -------------------------------- ### Registering an Object with Pyro Daemon Source: https://github.com/irmen/pyro5/blob/master/docs/source/servercode.rst Demonstrates how to register a new Pyro object with the daemon. The object is returned directly, and Pyro handles proxying automatically. ```python def some_pyro_method(self): thing=SomethingNew() self._pyroDaemon.register(thing) return thing ``` -------------------------------- ### List Nameserver Contents Source: https://github.com/irmen/pyro5/blob/master/docs/source/intro.rst Use this command to list the objects registered in the Pyro name server. This helps verify that your server objects are discoverable. ```bash $ pyro5-nsc list --------START LIST Pyro.NameServer --> PYRO:Pyro.NameServer@localhost:9090 metadata: {'class:Pyro5.nameserver.NameServer'} example.greeting --> PYRO:obj_198af10aa51f4fa8ab54062e65fad96a@localhost:44687 --------END LIST ``` -------------------------------- ### Create Proxy and Call Remote Methods Source: https://github.com/irmen/pyro5/blob/master/docs/source/clientcode.rst Once you have the URI of a Pyro object, create a Proxy to interact with it. You can call methods on the proxy as if it were the actual object, and handle return values or exceptions. ```python # Continuing our imaginary music server example. # Assume that uri contains the uri for the music server object. musicserver = Pyro5.api.Proxy(uri) try: ``` -------------------------------- ### Registering Object Names Source: https://github.com/irmen/pyro5/blob/master/docs/source/nameserver.rst Associates a URI with a logical name in the Name Server, allowing clients to refer to Pyro objects by name. The server registers its objects with the Daemon, gets a URI, and then registers that URI in the Name Server. ```APIDOC ## register(name, uri, safe=False) ### Description Registers an object (uri) under a logical name in the name server. ### Parameters #### Path Parameters - **name** (string) - Required - The logical name that the object will be known as. - **uri** (string or Pyro5.core.URI) - Required - The URI of the object (obtained from the daemon). - **safe** (bool) - Optional - If True, prevents registering the same name twice. Defaults to False, which overwrites existing registrations. ``` -------------------------------- ### Set PYRO_MAX_MESSAGE_SIZE Environment Variable Source: https://github.com/irmen/pyro5/blob/master/examples/maxsize/Readme.txt Set the PYRO_MAX_MESSAGE_SIZE environment variable to a small value before starting the echo server. This demonstrates how the server handles receiving messages that exceed the configured size limit, resulting in a logged error and connection closure. ```shell export PYRO_MAX_MESSAGE_SIZE=2000 ``` -------------------------------- ### Manual Object Resolution vs PYRONAME Source: https://github.com/irmen/pyro5/blob/master/docs/source/nameserver.rst Compares manual object resolution steps with the simplified approach using a PYRONAME URI. ```python nameserver=Pyro5.core.locate_ns() uri=nameserver.lookup("Department.BackupServer") proxy=Pyro5.client.Proxy(uri) proxy.backup() ``` ```python proxy=Pyro5.client.Proxy("PYRONAME:Department.BackupServer") proxy.backup() ``` -------------------------------- ### Pyro5 Greeting Server (No Name Server) Source: https://github.com/irmen/pyro5/blob/master/docs/source/intro.rst This is the server-side code for a simple Pyro greeting service. It exposes a method to clients and runs a daemon to handle requests. Save this as greeting-server.py. ```python import Pyro5.api @Pyro5.api.expose class GreetingMaker(object): def get_fortune(self, name): return "Hello, {0}. Here is your fortune message:\n" \ "Behold the warranty -- the bold print giveth and the fine print taketh away.".format(name) daemon = Pyro5.api.Daemon() # make a Pyro daemon uri = daemon.register(GreetingMaker) # register the greeting maker as a Pyro object print("Ready. Object uri =", uri) # print the uri so we can use it in the client later daemon.requestLoop() # start the event loop of the server to wait for calls ``` -------------------------------- ### Pyro5 Greeting Server (With Name Server) Source: https://github.com/irmen/pyro5/blob/master/docs/source/intro.rst Modified server code to register the greeting object with a logical name in the Pyro name server. This allows clients to look up the object by name instead of URI. Save this as greeting-server.py. ```python import Pyro5.api @Pyro5.api.expose class GreetingMaker(object): def get_fortune(self, name): return "Hello, {0}. Here is your fortune message:\n" \ "Tomorrow's lucky number is 12345678.".format(name) daemon = Pyro5.server.Daemon() # make a Pyro daemon ns = Pyro5.api.locate_ns() # find the name server uri = daemon.register(GreetingMaker) # register the greeting maker as a Pyro object ns.register("example.greeting", uri) # register the object with a name in the name server print("Ready.") daemon.requestLoop() # start the event loop of the server to wait for calls ``` -------------------------------- ### Register object with Name Server Source: https://github.com/irmen/pyro5/blob/master/docs/source/nameserver.rst Registers an object's URI under a logical name in the Name Server. Use safe=True to prevent registering the same name twice. ```python # Assuming 'ns_proxy' is a proxy to the Name Server # and 'obj_uri' is the URI of the object to register ns_proxy.register("my.object.name", obj_uri) ``` -------------------------------- ### Configure Pyro Daemon for NAT with nathost and natport Source: https://github.com/irmen/pyro5/blob/master/docs/source/tipstricks.rst Run a Pyro daemon behind a NAT router by specifying the external hostname and port using nathost and natport arguments. This ensures published URIs reflect the external address. ```python # running on server1.lan d = Pyro5.api.Daemon(port=9999, nathost="pyro.server.com", natport=5555) uri = d.register(Something, "thing") print(uri) # "PYRO:thing@pyro.server.com:5555" ``` -------------------------------- ### Pyro5 Greeting Client (With Name Server) Source: https://github.com/irmen/pyro5/blob/master/docs/source/intro.rst Simplified client code that uses the Pyro name server to locate the greeting object by its registered name. This eliminates the need for clients to know the object's URI directly. Save this as greeting-client.py. ```python import Pyro5.api name = input("What is your name? ").strip() greeting_maker = Pyro5.api.Proxy("PYRONAME:example.greeting") # use name server object lookup uri shortcut print(greeting_maker.get_fortune(name)) ``` -------------------------------- ### Implementing Pyro Callbacks with Exception Handling Source: https://github.com/irmen/pyro5/blob/master/docs/source/clientcode.rst Use the @Pyro5.api.expose and @Pyro5.api.callback decorators for methods intended to be called back from the server. This ensures exceptions are logged locally. ```python import Pyro5.api class Callback(object): @Pyro5.api.expose @Pyro5.api.callback def call(self): print("callback received from server!") return 1//0 # crash! ```