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

Uploaded CPython 3.12Windows x86-64

remotepy-0.0.1-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.1-cp311-cp311-win_amd64.whl (553.0 kB view details)

Uploaded CPython 3.11Windows x86-64

remotepy-0.0.1-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.1-cp310-cp310-win_amd64.whl (551.1 kB view details)

Uploaded CPython 3.10Windows x86-64

remotepy-0.0.1-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.1-cp39-cp39-win_amd64.whl (553.0 kB view details)

Uploaded CPython 3.9Windows x86-64

remotepy-0.0.1-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.1-cp312-cp312-win_amd64.whl.

File metadata

  • Download URL: remotepy-0.0.1-cp312-cp312-win_amd64.whl
  • Upload date:
  • Size: 532.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.1-cp312-cp312-win_amd64.whl
Algorithm Hash digest
SHA256 cc121b4cfb80c38279aef92cbafe946c2f637087c79991382f69d91ea0e2ebfd
MD5 a3a4fcd8c3ac0fcc00a972f389d3e388
BLAKE2b-256 abf40d281cc41faf57009cafa7dd502198f9b96cafc268f4d951d3c85b691fb6

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for remotepy-0.0.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl
Algorithm Hash digest
SHA256 b2d46fb590668ca2d55808dd1266cb3aa1ca83dfa1eeacf15b892544aeb9f1c4
MD5 b1a4e7af2b0973894244a113c9c15ee0
BLAKE2b-256 6d60879d310d03f7bc2f91057eb4b2a3b2d1f7327c3340a0eccb74c33ef22456

See more details on using hashes here.

File details

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

File metadata

  • Download URL: remotepy-0.0.1-cp311-cp311-win_amd64.whl
  • Upload date:
  • Size: 553.0 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.1-cp311-cp311-win_amd64.whl
Algorithm Hash digest
SHA256 6f6745a8ab510af58d1fb7b0dd686616711d60e072504898133846060e045c14
MD5 06cb89825e5ec6aa9ffaa8b0958a77f1
BLAKE2b-256 125220ded37ba53b7244f93896a5342f3dde163ce73996f063a15467f03e1bc2

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for remotepy-0.0.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl
Algorithm Hash digest
SHA256 c1698c966fb8b729c8a646bfa5bb468d14db3e4462855d6b8bc9aa8fbc84f909
MD5 20990dbacbca4975e0bb11151b15d2b8
BLAKE2b-256 ee67d01f80e58c8c3de150ed37be3e913623d2a268994a11ea47e2c416c095c2

See more details on using hashes here.

File details

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

File metadata

  • Download URL: remotepy-0.0.1-cp310-cp310-win_amd64.whl
  • Upload date:
  • Size: 551.1 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.1-cp310-cp310-win_amd64.whl
Algorithm Hash digest
SHA256 ec24af4e74e57577122b3a8168d816ec0b64350cf24fad30c81814bb5dff9bf5
MD5 2e4b338b086e8ac101eb6ad9ae1c173d
BLAKE2b-256 6b84a69e9a9b3ba2b56852e64518cbf6a9201eb725703efaa4a3170ca7e71fd9

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for remotepy-0.0.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl
Algorithm Hash digest
SHA256 6a025735fad4ac56949bf229bbd8579ebc0319e520439c081a6246f009b736a7
MD5 5394413131854e1276864481cf8806fc
BLAKE2b-256 76541441e03ca477763f0e416598d22dc75ce5601b00974a4e25327a1996b985

See more details on using hashes here.

File details

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

File metadata

  • Download URL: remotepy-0.0.1-cp39-cp39-win_amd64.whl
  • Upload date:
  • Size: 553.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.1-cp39-cp39-win_amd64.whl
Algorithm Hash digest
SHA256 1330b923afb5c575b4124eb72457428720db45dce47348f76f0b7a0f51d1a3ec
MD5 6b00c7c0cb2cb80bd7e42ca712067101
BLAKE2b-256 9df90e090dc06e1e337df5e26648b05a34c7841de63b56c11a5af3b7e9088232

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for remotepy-0.0.1-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.whl
Algorithm Hash digest
SHA256 e742478aadbbdfa3dfaba46140dceb8060d32121c24ddbc066495dde726ad485
MD5 dc5fc2e26ff3924df53d16be363de37c
BLAKE2b-256 7ea0cc71d507f9dfeeb16d712d6d371db3997e0597219b6ad6436f832abbb34e

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