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.3-cp312-cp312-win_amd64.whl (536.2 kB view details)

Uploaded CPython 3.12Windows x86-64

remotepy-0.0.3-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.3-cp311-cp311-win_amd64.whl (557.0 kB view details)

Uploaded CPython 3.11Windows x86-64

remotepy-0.0.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl (4.5 MB view details)

Uploaded CPython 3.11manylinux: glibc 2.17+ x86-64

remotepy-0.0.3-cp310-cp310-win_amd64.whl (555.1 kB view details)

Uploaded CPython 3.10Windows x86-64

remotepy-0.0.3-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.3-cp39-cp39-win_amd64.whl (624.9 kB view details)

Uploaded CPython 3.9Windows x86-64

remotepy-0.0.3-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.3-cp312-cp312-win_amd64.whl.

File metadata

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

File hashes

Hashes for remotepy-0.0.3-cp312-cp312-win_amd64.whl
Algorithm Hash digest
SHA256 151aaa7348f0dc9985834bdc67e4558083e439bb851e4c674f97a2dd1d1a1ab5
MD5 2b49170a67d21c4d16f9f9f2b5fe2f84
BLAKE2b-256 9d5a97601e3911c59e0537de0941d283dc98a510f327bf74f794121b76a42390

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for remotepy-0.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl
Algorithm Hash digest
SHA256 d174cbd2d631abff02351b164c6841f3fe1694b2e568873b97e248f88aa6637a
MD5 3a989829e227a95c4304f62a8981362d
BLAKE2b-256 b79cc61e465656e740c4c8d77e742d4ec008310c9c15813903321b32f3158579

See more details on using hashes here.

File details

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

File metadata

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

File hashes

Hashes for remotepy-0.0.3-cp311-cp311-win_amd64.whl
Algorithm Hash digest
SHA256 d25ec9f325550709eda1b66d31851fe2e8fcf4b5a8fa1cd21f3f3e37dff05f5c
MD5 78ddbc6e727c612dc6de793668236889
BLAKE2b-256 7c05b3430cc158ccdd6542a2568cb2abb4f69a46dddbab2f96a133d16e8d76ba

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for remotepy-0.0.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl
Algorithm Hash digest
SHA256 b5e913c4431c89498431e0191a0d2f45a3846b1f764b1a02743626f81bc712de
MD5 1857252df3b684ba73637ecaf89dca95
BLAKE2b-256 aa61b17bce376fe56caa6a01fc584e0c998221c75472cbd590fe756de75cedd6

See more details on using hashes here.

File details

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

File metadata

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

File hashes

Hashes for remotepy-0.0.3-cp310-cp310-win_amd64.whl
Algorithm Hash digest
SHA256 1d4904c01810ac58466151bcb1f45dcc3bcb41b8262ee21955480af83261f3f2
MD5 debdb88667d35df599a2147babf5f7b8
BLAKE2b-256 c96435346272f017590b49a7bb7780080d390adab6dd98077d5f083eff111a6d

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for remotepy-0.0.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl
Algorithm Hash digest
SHA256 1310373e4454f5eddd116e6ef51dc2ec79a9549f4178b4f250f6fee4c35d67f0
MD5 6c9aa0762ed00c4961f4159a4771d6e7
BLAKE2b-256 290632691d1c372c545e72fba59bbf8961c166b4e85239264941d80cc1aa4db5

See more details on using hashes here.

File details

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

File metadata

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

File hashes

Hashes for remotepy-0.0.3-cp39-cp39-win_amd64.whl
Algorithm Hash digest
SHA256 e8de6125d9fac111ace2739737012b593b53a3f7def8ce21ccb54cd137edf7b9
MD5 ae23a6a59d467f9a76830378cb361303
BLAKE2b-256 dd518396a12d4a7c4b5c21891b0592aa82e91e224d8ddfb41a56759038193bbb

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for remotepy-0.0.3-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.whl
Algorithm Hash digest
SHA256 6791f03105a6e29c2f4b1ad0494f5d860b255a273620a22305da74dc01e44f71
MD5 9444e4a877c39be516c9715aad49a4ea
BLAKE2b-256 cbb44d0c2e6e09e30601afa730d84a2629e48497912c72b55a40fd743d8220d1

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