Skip to main content

remotepy allows Python functions to be called remotely from multiple languages including JavaScript, CSharp and Python

Project description

Remote Py

Remote Py is a powerful RPC (Remote Procedure Call) framework that allows you to write Python functions and expose them as remote services. It provides client interfaces in multiple languages including JavaScript, C#, and Python, enabling seamless cross-platform communication over WebSockets.

Features

  • Multi-language Support: Call Python functions from JavaScript (browser), C#, and Python clients
  • Bidirectional Communication: Full-duplex communication using WebSockets for real-time interaction
  • Easy-to-Use API: Simple decorator-based API (@remotepy_func, @remotepy_class) for exposing functions
  • Session Management: Built-in session handling and authentication support with SessionServer
  • Real-time Messaging: Pub/Sub broadcasting capabilities for event-driven architectures
  • Async Support: Full support for async/await Python functions and generators
  • Streaming: Support for generators and async generators for streaming large datasets
  • Security Features:
    • Rate limiting (100 calls per function per minute by default)
    • Input validation
    • Password sanitization in logs
    • SQL injection protection
  • SSL/TLS Support: Secure WebSocket connections with SSL/TLS
  • Binary Protocol: Efficient message serialization using MessagePack
  • Error Handling: Comprehensive error handling with sanitized error messages

Installation

Production PyPI

pip install remotepy

Test PyPI

If installing from test.pypi.org, you must also specify the regular PyPI as an extra index because test PyPI doesn't have all dependencies:

pip install --index-url https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple/ remotepy

Requirements

All required dependencies are automatically installed with the package. The main dependencies include:

  • numpy - Numerical operations
  • service_identity - Service identity verification
  • twisted - Network framework
  • autobahn - WebSocket implementation
  • cryptography - Cryptographic functions
  • zmq - ZeroMQ messaging
  • msgpack - Binary serialization
  • python-dotenv - Environment variable management

Quick Start

Basic Server Example

Create a server file (e.g., server.py):

from remotepy import *

@remotepy_class
class MyPythonServer(WebSocketRPCServerProtocol, SessionServer):
    def onConnect(self, request):
        print("Client connecting: {}".format(request.peer))
    
    @remotepy_func
    def add(self, a, b):
        """
        Adds two numbers together.
        
        :param a: First number
        :param b: Second number
        :return: Sum of a and b
        """
        return a + b
    
    @remotepy_func
    def greet(self, name):
        """Greets a user by name."""
        return f"Hello, {name}!"
    
    def onClose(self, wasClean, code, reason):
        print("Client closing connection: ", code, reason)

# Initialize server with database configuration (optional)
db_config = {
    'host': 'localhost',
    'user': 'your_user',
    'password': 'your_password',
    'database': 'your_database'
}

server = MyPythonServer(db_config)
server.run("127.0.0.1", 8082)

Server with SSL/TLS

For secure connections:

server = MyPythonServer(db_config)
server.run_ssl(
    "0.0.0.0", 
    8443, 
    "path/to/private.pem", 
    "path/to/fullchain.pem"
)

Advanced Features

Async Functions

Remote Py supports both synchronous and asynchronous Python functions:

@remotepy_class
class MyAsyncServer(WebSocketRPCServerProtocol):
    @remotepy_func
    async def async_process_data(self, data):
        """Process data asynchronously."""
        # Simulate async operation
        await asyncio.sleep(1)
        return {"processed": data, "status": "complete"}
    
    @remotepy_func
    def sync_process_data(self, data):
        """Process data synchronously."""
        return {"processed": data, "status": "complete"}

Streaming with Generators

Stream large datasets efficiently using generators:

@remotepy_class
class DataServer(WebSocketRPCServerProtocol):
    @remotepy_func
    def stream_data(self, count):
        """Stream data items one by one."""
        for i in range(count):
            yield {"index": i, "data": f"item_{i}"}
    
    @remotepy_func
    async def async_stream_data(self, count):
        """Stream data asynchronously."""
        for i in range(count):
            await asyncio.sleep(0.1)
            yield {"index": i, "data": f"item_{i}"}

Session Management

Use SessionServer for user authentication and session handling:

from remotepy import *

@remotepy_class
class SecureServer(WebSocketRPCServerProtocol, SessionServer):
    def __init__(self, db_config):
        super().__init__(db_config)
        # Configure email settings for password reset
        self.set_email_config(
            user="your-email@gmail.com",
            server="smtp.gmail.com",
            port=587
        )
    
    @remotepy_method
    def validateLogin(self, sessionid, username, password, remember, currentUrl, afterLoginUrl):
        """Validate user login credentials."""
        # Implementation handled by SessionServer
        pass
    
    @remotepy_method
    def getSessionId(self):
        """Get current session ID."""
        return self.SessionState.getSessionId()

Protected Functions

Use decorators to protect functions that require authentication:

from remotepy.websocket.remotepy import remotepy_login_required, remotepy_permitted_to

@remotepy_class
class ProtectedServer(WebSocketRPCServerProtocol, SessionServer):
    @remotepy_func
    @remotepy_login_required
    def get_user_data(self):
        """Requires user to be logged in."""
        return {"user": "data"}
    
    @remotepy_func
    @remotepy_permitted_to("admin")
    def admin_function(self):
        """Requires admin permission."""
        return {"admin": "data"}

Pub/Sub Broadcasting

Use PubSubBroadcastServerFactory for real-time event broadcasting:

from remotepy import PubSubBroadcastServerFactory

@remotepy_class
class BroadcastServer(WebSocketRPCServerProtocol):
    def __init__(self):
        super().__init__()
        # Your initialization code
    
    @remotepy_func
    def broadcast_message(self, message):
        """Broadcast a message to all connected clients."""
        # Implementation for broadcasting
        pass

# Use PubSubBroadcastServerFactory for pub/sub functionality
server = BroadcastServer()
server.run("127.0.0.1", 8082, ServerFactory=PubSubBroadcastServerFactory)

Configuration

Environment Variables

Remote Py supports configuration via environment variables. Create a .env file:

REMOTEPY_EMAIL_USER=your-email@gmail.com
REMOTEPY_EMAIL_PASSWORD=your-app-password
REMOTEPY_EMAIL_SERVER=smtp.gmail.com
REMOTEPY_EMAIL_PORT=587
REMOTEPY_RESET_PASSWORD_EMAIL=noreply@yourdomain.com
REMOTEPY_DOMAIN_NAME=https://www.yourdomain.com

If environment variables are not set, Remote Py will use default values for backward compatibility.

Rate Limiting

Rate limiting is enabled by default (100 calls per function per 60 seconds). You can customize this:

# In your server class __init__ or after instantiation
server._rate_limit_window = 60  # Time window in seconds
server._rate_limit_max_calls = 200  # Max calls per window

Client Examples

JavaScript Client

Installation:

The JavaScript client is available as a separate package. For web applications, include the client library in your HTML:

<script language="JavaScript" src="js/remotepy.1.0.0.min.js"></script>

Usage Example:

<!DOCTYPE html>
<html>
<head>
    <title>RemotePy Client</title>
</head>
<body>
    <script language="JavaScript" src="js/remotepy.1.0.0.min.js"></script>
    <script language="JavaScript">
        var RemotePy = new RemotePyClient();
        
        window.onload = function() {
            RemotePy.serverName = 'ws://localhost:8082';
            RemotePy.start();
        }

        RemotePy.onopen = function() {
            console.log("Connected to server");
            
            // Call a remote function
            RemotePy.MyPythonServer.add(2, 4, function(sum) {
                console.log("Result:", sum);  // Output: 6
            });
            
            // Call with error handling
            RemotePy.MyPythonServer.greet("World", function(result) {
                console.log(result);  // Output: "Hello, World!"
            }, function(error) {
                console.error("Error:", error);
            });
        }

        RemotePy.onclose = function() {
            console.log("Connection closed");
        }
        
        RemotePy.onerror = function(error) {
            console.error("Connection error:", error);
        }
    </script>
</body>
</html>

Python Client

Installation:

pip install remotepy_client

Usage Example:

from remotepy_client.remotepy_rpc_client import RemotePyRPCClientSync

# Server configuration
broker = "ws://localhost"
port = 8082
verbose = False
server_url = f"{broker}:{port}"

# Connect to remotepy server to get the metadata for offered functions
client = RemotePyRPCClientSync(server_url, verbose)

# Build the client connectivity code for all the server functions
client.buildService('')

# Get access to available services
MyPythonServerEngine = client.getService('MyPythonServer')

# Connect to the remotepy server to call server functions
MyPythonServer = MyPythonServerEngine(f"{broker}:{port}", verbose)

# Call remotepy server function synchronously
result = MyPythonServer.add(a=5, b=6, callback=None)
print(result)  # Output: 11

# Call with callback
def handle_result(result):
    print(f"Received result: {result}")

MyPythonServer.greet(name="Python Client", callback=handle_result)

# Wait for all the threads to finish
client.thread().join()

Async Python Client Example:

import asyncio
from remotepy_client.remotepy_rpc_client import RemotePyRPCClientAsync

async def main():
    server_url = "ws://localhost:8082"
    client = RemotePyRPCClientAsync(server_url)
    
    await client.connect()
    client.buildService('')
    
    MyPythonServer = client.getService('MyPythonServer')(server_url)
    
    # Call async function
    result = await MyPythonServer.async_process_data({"key": "value"})
    print(result)
    
    await client.close()

asyncio.run(main())

Error Handling

Remote Py provides comprehensive error handling:

  • Input Validation: Automatic validation of RPC call parameters
  • Rate Limiting: Protection against excessive function calls
  • Error Sanitization: Passwords and sensitive data are automatically redacted from error messages
  • Connection Handling: Graceful handling of disconnected clients

Error responses follow this format:

{
    "funcName": "function_name",
    "callId": "call_id",
    "error": "Error message (with sensitive data redacted)"
}

Security Features

Rate Limiting

By default, each function is rate-limited to 100 calls per 60-second window. This prevents abuse and DoS attacks.

Input Validation

All RPC calls are validated:

  • Function names must be strings (max 256 characters)
  • Arguments must be dictionaries
  • Potentially dangerous function names are logged (but not blocked for compatibility)

Password Protection

  • Passwords are never logged
  • Error messages are sanitized to remove password information
  • Session IDs are validated and cleaned up after use

SQL Injection Protection

  • Schema names are sanitized before use in SQL queries
  • Parameterized queries are used for all database operations

API Reference

Decorators

  • @remotepy_class: Decorates a class to make it a RemotePy server
  • @remotepy_func: Exposes a function for remote calls
  • @remotepy_method: Exposes a method for remote calls (used with SessionServer)
  • @remotepy_login_required: Requires user to be logged in
  • @remotepy_permitted_to(action): Requires specific permission

Server Methods

  • server.run(ip, port, ServerFactory=None): Start server on specified IP and port
  • server.run_ssl(ip, port, private_pem_file, fullchain_pem_file, ServerFactory=None): Start server with SSL/TLS

SessionServer Methods

  • validateLogin(sessionid, username, password, remember, currentUrl, afterLoginUrl): Validate user credentials
  • getSessionId(): Get current session ID
  • getNewSessionId(): Generate a new session ID
  • isLoggedIn(sessionid): Check if user is logged in
  • logOut(): Log out current session
  • set_email_config(...): Configure email settings for password reset

Best Practices

  1. Use Type Hints: Add type hints to your functions for better documentation
  2. Error Handling: Always handle errors appropriately in your functions
  3. Session Management: Use SessionServer for applications requiring authentication
  4. Rate Limiting: Adjust rate limits based on your application's needs
  5. SSL/TLS: Always use SSL/TLS in production environments
  6. Environment Variables: Store sensitive configuration in environment variables
  7. Logging: Use Python's logging module instead of print statements

Troubleshooting

Connection Issues

  • Ensure the server is running and accessible
  • Check firewall settings
  • Verify WebSocket URL format (ws:// or wss://)

Rate Limiting

If you encounter rate limit errors, either:

  • Increase the rate limit settings
  • Reduce the frequency of function calls
  • Implement client-side throttling

Session Issues

  • Ensure database configuration is correct
  • Verify session IDs are being passed correctly
  • Check that SessionServer is properly initialized

Documentation

For more information, visit https://www.remotepy.com

License

This project is proprietary software. All rights reserved. See the LICENSE file for details.

Author

Faraz Farukh Tamboli

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distributions

No source distribution files available for this release.See tutorial on generating distribution archives.

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

remotepy-0.0.2-cp312-cp312-win_amd64.whl (533.1 kB view details)

Uploaded CPython 3.12Windows x86-64

remotepy-0.0.2-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl (4.5 MB view details)

Uploaded CPython 3.12manylinux: glibc 2.17+ x86-64

remotepy-0.0.2-cp311-cp311-win_amd64.whl (554.1 kB view details)

Uploaded CPython 3.11Windows x86-64

remotepy-0.0.2-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl (4.4 MB view details)

Uploaded CPython 3.11manylinux: glibc 2.17+ x86-64

remotepy-0.0.2-cp310-cp310-win_amd64.whl (552.3 kB view details)

Uploaded CPython 3.10Windows x86-64

remotepy-0.0.2-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl (4.2 MB view details)

Uploaded CPython 3.10manylinux: glibc 2.17+ x86-64

remotepy-0.0.2-cp39-cp39-win_amd64.whl (554.0 kB view details)

Uploaded CPython 3.9Windows x86-64

remotepy-0.0.2-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.whl (4.2 MB view details)

Uploaded CPython 3.9manylinux: glibc 2.17+ x86-64

File details

Details for the file remotepy-0.0.2-cp312-cp312-win_amd64.whl.

File metadata

  • Download URL: remotepy-0.0.2-cp312-cp312-win_amd64.whl
  • Upload date:
  • Size: 533.1 kB
  • Tags: CPython 3.12, Windows x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.9.7

File hashes

Hashes for remotepy-0.0.2-cp312-cp312-win_amd64.whl
Algorithm Hash digest
SHA256 91136778836803364f6ceac95468b20d64378eb542654e027a87aa82a6b0c5ef
MD5 431125a871cacc15de27d7e631ec4df6
BLAKE2b-256 7186f2ea89687f392f3ad6a01afc3e585f1f01a3ddb2d1834bf2db94ee9f1796

See more details on using hashes here.

File details

Details for the file remotepy-0.0.2-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl.

File metadata

File hashes

Hashes for remotepy-0.0.2-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl
Algorithm Hash digest
SHA256 fbd63f7dcff11e7f4708c4f847bbf6a552710205e0f4ad6df67d4e19479e2239
MD5 e69ab51cc46620d97ff9a46d6c5d4279
BLAKE2b-256 27bc8bb52b9f72b3b655682d4131de87677dbf41b2c5ef068e8d1fa7ac7e21c3

See more details on using hashes here.

File details

Details for the file remotepy-0.0.2-cp311-cp311-win_amd64.whl.

File metadata

  • Download URL: remotepy-0.0.2-cp311-cp311-win_amd64.whl
  • Upload date:
  • Size: 554.1 kB
  • Tags: CPython 3.11, Windows x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.9.7

File hashes

Hashes for remotepy-0.0.2-cp311-cp311-win_amd64.whl
Algorithm Hash digest
SHA256 695cb9816e3456e626b1005fcd407b9f31d37842e315810d461cf552ca30fdbe
MD5 1037b586b03adae249a0c574fea46863
BLAKE2b-256 f8ad7d2d99b12e4241a76a612928ca349bdcebbb89977bf5be869468e6d60fb8

See more details on using hashes here.

File details

Details for the file remotepy-0.0.2-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl.

File metadata

File hashes

Hashes for remotepy-0.0.2-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl
Algorithm Hash digest
SHA256 d40421d847be955bbdf49f5ff653ac4379902d2c2594a5b08e65b1455900503f
MD5 23dc1e2c2c44a3421e41be150ba8bc12
BLAKE2b-256 717682f364739e94fa6ca707e569da35801f172ae37373ec5fbc22109762094b

See more details on using hashes here.

File details

Details for the file remotepy-0.0.2-cp310-cp310-win_amd64.whl.

File metadata

  • Download URL: remotepy-0.0.2-cp310-cp310-win_amd64.whl
  • Upload date:
  • Size: 552.3 kB
  • Tags: CPython 3.10, Windows x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.9.7

File hashes

Hashes for remotepy-0.0.2-cp310-cp310-win_amd64.whl
Algorithm Hash digest
SHA256 f50c353471da9e462fd2cf9281dd542e92880649e81d65b535697aeff77edbb1
MD5 c4d9cd95ea761c4ee283d710a844fd99
BLAKE2b-256 4d0fea44755cdc163c858603c971548aba0613d26860a6815373caf632d22e3b

See more details on using hashes here.

File details

Details for the file remotepy-0.0.2-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl.

File metadata

File hashes

Hashes for remotepy-0.0.2-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl
Algorithm Hash digest
SHA256 133bf2fdbb002fbde7b40678db30902d9d0d7272af1f866b8aa2064ce8e4c597
MD5 c2dd42b19e1af46a2c4f0b0e9c6b78c4
BLAKE2b-256 86777696ef6595bae2298cdc04bb8b79456d3b7c5a9bac7ae679bb7131c2a8e6

See more details on using hashes here.

File details

Details for the file remotepy-0.0.2-cp39-cp39-win_amd64.whl.

File metadata

  • Download URL: remotepy-0.0.2-cp39-cp39-win_amd64.whl
  • Upload date:
  • Size: 554.0 kB
  • Tags: CPython 3.9, Windows x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.9.7

File hashes

Hashes for remotepy-0.0.2-cp39-cp39-win_amd64.whl
Algorithm Hash digest
SHA256 70468a20ef1197fe45cd4c6842e212fcee85dac64c866a23505286b2982e06d5
MD5 021dd3b9ab24b4dc2dcbe6c22978574d
BLAKE2b-256 bcefaad452cc17920e2f7df7363568acbaee600a13e56638fffd7d8aa30f798e

See more details on using hashes here.

File details

Details for the file remotepy-0.0.2-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.whl.

File metadata

File hashes

Hashes for remotepy-0.0.2-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.whl
Algorithm Hash digest
SHA256 1f6fe242d26e3f58e553d91b5de040d516fb65d1f9e52bae9e7b20f160a99a91
MD5 049977a6a10baea2ee0a001083aca941
BLAKE2b-256 92a4a0afa51ea81622229d6e4480d758aa44d858e423a79600028ebdc9746b46

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page