Registry / http-networking / pyro5
library5.16pypypi✓ verified 87d ago

Pyro5 is a Python library for remote object communication, enabling client-server interactions across different processes or machines. It's the fifth major version of the Pyro project, emphasizing ease of use and flexibility. As of version 5.16, the project has entered a low maintenance mode, with active development paused unless critical bugs are reported.

pip install pyro5
INSTALL
IMPORT
SIG · PYRO5
P
pyro5
http-networkingpythonv5.16
Install
1.6s avg
Import
118ms
Disk
17MB
Pass rate
10/ 10
Env Coverage10 / 10
glibc
3.93.13
musl
3.93.13
Install & Compatibility
Where this runs
tested against v5.16 · pip install
no network on importno background threads
Install × environment matrix
Each cell = how many times install + import succeeded across repeated harness runs. Partial = flaky.
glibc = Debian/Ubuntu slim · musl = Alpine Linux
musl
py 3.103.920 runs
installs and imports cleanly · install 0.0s · import 0.123s · 18.4MB
glibc
py 3.103.920 runs
installs and imports cleanly · install 1.6s · import 0.112s · 19MB
17MB installed
● package 17MB
Code
Verified usage

Verified import paths — ran on the pinned version, not inferred.

Daemon
from Pyro5.api import Daemon
expose
from Pyro5.api import expose
locate_ns
from Pyro5.api import locate_ns
Proxy
from Pyro5.api import Proxy
URI
from Pyro5.api import URI
Pyro5.server
from Pyro5.api import Daemon
import Pyro5.server
While 'Pyro5.server' is a submodule, its core components like Daemon are usually accessed via the unified 'Pyro5.api' entry point. Direct import was also problematic in older versions (v5.12).

This quickstart demonstrates a basic Pyro5 client-server interaction. It defines a server class, registers it with a Pyro Name Server, and then a client looks up the server and calls its methods. Before running, ensure you start the Pyro Name Server in a *separate* terminal using `python -m Pyro5.nameserver`. This is crucial for name lookup. The provided code attempts to run both server and client within the same script using threads for convenience, but in typical usage, they are separate processes, potentially on different machines.

import Pyro5.api import time import threading # --- Server side (run in one terminal) --- @Pyro5.api.expose class MyServer: def greet(self, name): return f"Hello, {name}! This is Pyro5." def echo(self, message): return f"Server received: {message}" def get_time(self): return time.time() def run_server(): # Start a Name Server in a separate terminal: python -m Pyro5.nameserver # Or, start one programmatically if not using a shared nameserver # For simplicity, we'll try to connect to one assumed to be running on localhost try: ns = Pyro5.api.locate_ns(host="localhost") except Pyro5.errors.NamingError: print("No Name Server found. Please start one: python -m Pyro5.nameserver") return daemon = Pyro5.api.Daemon(host="localhost") uri = daemon.register(MyServer, "example.myserver") # Register with a name ns.register("example.myserver", uri) # Register the URI with the Name Server print(f"Server URI: {uri}") print("Server ready. Object registered as 'example.myserver'.") print("Starting event loop (Ctrl+C to stop)...") daemon.requestLoop() # --- Client side (run in another terminal) --- def run_client(): # Locate the Name Server to find the object try: ns = Pyro5.api.locate_ns(host="localhost") except Pyro5.errors.NamingError: print("No Name Server found. Cannot connect to server.") return uri = ns.lookup("example.myserver") # Look up the object's URI by its name # Create a proxy to the remote object with Pyro5.api.Proxy(uri) as server_proxy: print(f"Greeting: {server_proxy.greet('Pyro User')}") print(f"Echo: {server_proxy.echo('This is a test message.')}") print(f"Remote time: {server_proxy.get_time()}") if __name__ == '__main__': # This quickstart demonstrates client-server. # For actual usage, run server and client in separate processes. print("--- Pyro5 Quickstart ---") print("To run, first start the Pyro Name Server in a *separate* terminal:") print(" python -m Pyro5.nameserver ") print("Then run this script. It will run the server, wait, then the client.") print("Or, copy the server part to 'server.py' and client to 'client.py' and run them separately.") # Simplified running for quickstart; normally they are separate processes server_thread = threading.Thread(target=run_server) server_thread.daemon = True # Allow main program to exit even if server is running server_thread.start() print("\nWaiting for server to start and register...") time.sleep(2) # Give server a moment to start and register print("\n--- Running Client ---") run_client() print("\nClient finished.") # The server thread will continue running until Ctrl+C if it was main, # but here it's a daemon thread so it will exit with main.
Debug
Known issues
breakingPyro5 has aggressively dropped support for older Python versions. As of v5.16, only Python 3.10 and newer are supported.
fix
Ensure your environment uses Python 3.10 or newer. Upgrade your Python interpreter if necessary.
affects: v5.12, v5.13, v5.15, v5.16
deprecatedThe Pyro5 project is in a 'super low maintenance mode' as of v5.16. While critical bug fixes might be applied, active development of new features or significant changes is not planned.
fix
Be aware that new features or rapid bug fixes are unlikely. Consider contributing or forking the project if significant changes are required for your application.
affects: v5.16+
gotchaThe `@expose` decorator on a class does not automatically expose methods inherited from its base classes. Each class in the inheritance hierarchy must explicitly use `@expose` on its methods or class to make them remotely accessible.
fix
Explicitly apply `@expose` to methods in each inherited class where remote access is desired.
affects: All 5.x versions (behavior clarified in v5.16 docs)
breakingThe `Daemon.serve()` method's `host` parameter no longer defaults to an empty string `''` but `None`. This can change binding behavior, especially for IPv6 or specific interface binding.
fix
Explicitly specify the `host` parameter (e.g., `'0.0.0.0'` for all interfaces, `'localhost'`, or a specific IP address) when creating `Daemon` or calling `daemon.serve()` to ensure desired binding behavior.
affects: v5.14+
gotchaUsing `@expose` on `staticmethod` or `classmethod` in Python 3.10+ caused issues due to API changes in Python. While fixed in v5.13.1, older minor versions could be affected.
fix
Upgrade to Pyro5 v5.13.1 or newer if using Python 3.10+ and relying on exposed static/class methods.
affects: v5.13 and possibly earlier versions when run on Python 3.10+
Errors
Common errors & fixes
ImportError: cannot import name 'server' from 'Pyro5'
Attempting to import `server` from the top-level `Pyro5` package. Core components like `Daemon` are primarily exposed through `Pyro5.api`.
fix
Always use `from Pyro5.api import ...` for accessing core Pyro5 classes and functions. For example, `from Pyro5.api import Daemon, expose, locate_ns, Proxy`.
Pyro5.errors.NamingError: no such object with name "example.myserver"
The Pyro Name Server cannot find the registered object. This typically means the server object was not registered, the Name Server isn't running, or the client is looking up a different name, host, or port.
fix
1. Ensure the Pyro Name Server is running (`python -m Pyro5.nameserver`). 2. Verify the server registered its object correctly (e.g., `ns.register('name', uri)`). 3. Confirm the client is using the exact same name for lookup and connecting to the correct Name Server host/port.
AttributeError: remote object has no attribute 'my_method'
The method `my_method` on the remote object was not exposed for remote calls. Pyro5 requires methods or classes to be explicitly exposed.
fix
Ensure the remote class itself is decorated with `@Pyro5.api.expose` (which exposes all public methods), or if not, that each specific method intended for remote calls is decorated with `@Pyro5.api.expose`. Remember that methods inherited from base classes also need explicit `@expose` if the base class isn't itself exposed.
Pyro5.errors.DaemonError: no valid URI for the given object: <object at ...>
This error occurs when an object is registered with the Daemon, but there's a problem generating or associating a valid URI with it, often due to configuration issues or the object not being suitable for exposure.
fix
Ensure the object passed to `daemon.register()` is properly set up for exposure (e.g., its class or methods are `@expose`d). Check the Daemon's host and port configuration to ensure it can bind correctly and generate a reachable URI. For example, explicitly set `Daemon(host='0.0.0.0')` if you need to be reachable from other machines.
Upgrade
Version history
5.16latest on PyPI · released Dec 21, 2025
Audit
Dependencies
serpentrequiredUsed for object serialization.
Agent activity
14 hits · last 30 days
node
14
Resources
pyro5 — pip install pyro5 · libregistry