module RubyPython

RubyPython is a bridge between the Ruby and Python interpreters. It embeds a Python interpreter in the Ruby application's process using FFI and provides a means for wrapping, converting, and calling Python objects and methods.

Usage

The Python interpreter must be started before the RubyPython bridge is functional. The user can either manually manage the running of the interpreter as shown below, or use the RubyPython.run or RubyPython.session methods to automatically start and stop the interpreter.

RubyPython.start
cPickle = RubyPython.import "cPickle"
puts cPickle.dumps("RubyPython is awesome!").rubify
RubyPython.stop

Constants

PyMain

The accessible instance of PyMainClass.

VERSION

Public Class Methods

Type(name) click to toggle source

Creates a Ruby class that inherits from a proxied Python object.

# File lib/rubypython/type.rb, line 3
def self.Type(name)
  mod, match, klass = name.rpartition(".")
  pymod = RubyPython.import(mod)
  pyclass = pymod.pObject.getAttr(klass)
  rclass = Class.new(RubyPyProxy) do
    define_method(:initialize) do |*args|
      args = PyObject.convert(*args)
      pTuple = PyObject.buildArgTuple(*args)
      pReturn = pyclass.callObject(pTuple)
      if PythonError.error?
        raise PythonError.handle_error
      end
      @pObject = pReturn
    end
  end
  return rclass
end
generator() { |*args| ... } click to toggle source

Creates a Ruby lambda that acts like a Python generator. Uses RubyPython.generator_type and Fiber to work the generator as a coroutine.

Note: This method only exists in the RubyPython if the Fiber exists.

# File lib/rubypython/pygenerator.rb, line 40
def generator
  return lambda do |*args|
    fib = Fiber.new do
      yield *args
      Python.PyErr_SetNone(Python.PyExc_StopIteration)
      ::FFI::Pointer::NULL
    end
    generator_type.__call__(lambda { fib.resume })
  end
end
generator_type() click to toggle source

Creates a Python generator object called rubypython_generator that accepts a callback and yields to it.

Note: This method only exists in the RubyPython if the Fiber exists.

# File lib/rubypython/pygenerator.rb, line 17
      def generator_type
        @generator_type ||= lambda do
          code = <<-EOM
def rubypython_generator(callback):
  while True:
    yield callback()
          EOM

          globals = PyObject.new({ "__builtins__" => PyMain.builtin.pObject, })
          empty_hash = PyObject.new({})
          ptr = Python.PyRun_String(code, Python::PY_FILE_INPUT, globals.pointer, empty_hash.pointer)
          ptr = Python.PyRun_String("rubypython_generator", Python::PY_EVAL_INPUT, globals.pointer, empty_hash.pointer)
          raise PythonError.handle_error if PythonError.error?
          RubyPyProxy.new(PyObject.new(ptr))
        end.call
      end
import(mod_name) click to toggle source

Import a Python module into the interpreter and return a proxy object for it.

This is the preferred way to gain access to Python objects.

mod_name

The name of the module to import.

# File lib/rubypython.rb, line 104
def import(mod_name)
  if defined? Python.Py_IsInitialized and Python.Py_IsInitialized != 0
    pModule = Python.PyImport_ImportModule mod_name
    raise PythonError.handle_error if PythonError.error?
    pymod = PyObject.new pModule
    RubyPyModule.new(pymod)
  else
    raise "Python has not been started."
  end
end
python() click to toggle source

Returns an object describing the active Python interpreter. Returns nil if there is no active interpreter.

# File lib/rubypython.rb, line 192
def python
  if self.const_defined? :Runtime
    self::Runtime
  else
    nil
  end
end
run(options = {}) { block to execute in RubyPython context } click to toggle source

Starts the Python interpreter (optionally with options) and executes the provided block in the RubyPython module scope. When the block exits for any reason, the Python interpreter is stopped automatically.

The last executed expression of the block is returned. Be careful that the last expression of the block does not return a RubyPyProxy object, because the proxy object will be invalidated when the interpreter is stopped.

options

Configures the interpreter prior to starting it. Principally used to provide an alternative Python interpreter to start.

NOTE: In the current version of RubyPython, it is possible to change Python interpreters in a single Ruby process execution, but it is strongly discouraged as this may lead to segmentation faults. This feature is highly experimental and may be disabled in the future.

# File lib/rubypython.rb, line 161
def run(options = {}, &block)
  start(options)
  self.module_eval(&block)
ensure
  stop
end
session(options = {}) { block to execute } click to toggle source

Starts the Python interpreter (optionally with options) and yields to the provided block. When the block exits for any reason, the Python interpreter is stopped automatically.

The last executed expression of the block is returned. Be careful that the last expression of the block does not return a RubyPyProxy object, because the proxy object will be invalidated when the interpreter is stopped.

options

Configures the interpreter prior to starting it. Principally used to provide an alternative Python interpreter to start.

NOTE: In the current version of RubyPython, it is possible to change Python interpreters in a single Ruby process execution, but it is strongly discouraged as this may lead to segmentation faults. This feature is highly experimental and may be disabled in the future.

# File lib/rubypython.rb, line 134
def session(options = {})
  start(options)
  yield
ensure
  stop
end
start(options = {}) click to toggle source
Starts the \Python interpreter. One of +RubyPython.start+,

RubyPython.session+, or RubyPython.run must be run before using any Python code. Returns true if the interpreter was started; false otherwise.

options

Configures the interpreter prior to starting it. Principally used to provide an alternative Python interpreter to start.

With no options provided:

RubyPython.start
sys = RubyPython.import 'sys'
p sys.version # => "2.6.6"
RubyPython.stop

With an alternative Python executable:

RubyPython.start(:python_exe => 'python2.7')
sys = RubyPython.import 'sys'
p sys.version # => "2.7.1"
RubyPython.stop
# File lib/rubypython.rb, line 53
def start(options = {})
  RubyPython::Python.synchronize do
    # Has the Runtime interpreter been defined?
    if self.const_defined?(:Runtime)
      # If this constant is defined, then yes it is. Since it is, let's
      # see if we should print a warning to the user.
      unless Runtime == options
        warn "The Python interpreter has already been loaded from #{Runtime.python} and cannot be changed in this process. Continuing with the current runtime."
      end
    else
      interp = RubyPython::Interpreter.new(options)
      if interp.valid?
        self.const_set(:Runtime, interp)
      else
        raise RubyPython::InvalidInterpreter, "An invalid interpreter was specified."
      end
    end
    
    unless defined? RubyPython::Python.ffi_libraries
      Runtime.__send__(:infect!, RubyPython::Python)
    end

    return false if RubyPython::Python.Py_IsInitialized != 0
    RubyPython::Python.Py_Initialize
    notify :start
    true
  end
end
start_from_virtualenv(virtualenv) click to toggle source

Starts the Python interpreter for a virtualenv virtual environment. Returns true if the interpreter was started.

virtualenv

The root path to the virtualenv-installed Python interpreter.

RubyPython.start_from_virtualenv('/path/to/virtualenv')
sys = RubyPython.import 'sys'
p sys.version # => "2.7.1"
RubyPython.stop

NOTE: In the current version of RubyPython, it is possible to change Python interpreters in a single Ruby process execution, but it is strongly discouraged as this may lead to segmentation faults. This feature is highly experimental and may be disabled in the future.

# File lib/rubypython.rb, line 184
def start_from_virtualenv(virtualenv)
  result = start(:python_exe => File.join(virtualenv, "bin", "python"))
  activate_virtualenv
  result
end
stop() click to toggle source

Stops the Python interpreter if it is running. Returns true if the intepreter is stopped. All wrapped Python objects are invalid after invocation of this method. If you need the values within the Python proxy objects, be sure to call +RubyPyProxy#rubify+ on them.

# File lib/rubypython.rb, line 86
def stop
  RubyPython::Python.synchronize do
    if defined? Python.Py_IsInitialized and Python.Py_IsInitialized != 0
      Python.Py_Finalize
      notify :stop
      true
    else
      false
    end
  end
end
yield(*args) click to toggle source

Performs a Fiber.yield with the provided arguments, continuing the coroutine execution of the generator.

Note: This method only exists in the RubyPython if the Fiber exists.

# File lib/rubypython/pygenerator.rb, line 56
def yield(*args)
  Fiber.yield(*args)
end

Private Class Methods

activate_virtualenv() click to toggle source

Used to activate the virtualenv.

# File lib/rubypython.rb, line 201
def activate_virtualenv
  imp = import("imp")
  imp.load_source("activate_this",
                  File.join(File.dirname(RubyPython::Runtime.python),
                  "activate_this.py"))
end
add_observer(object) click to toggle source
# File lib/rubypython.rb, line 209
def add_observer(object)
  @observers ||= []
  @observers << object
  true
end
notify(status) click to toggle source
# File lib/rubypython.rb, line 216
def notify(status)
  @observers ||= []
  @observers.each do |o|
    next if nil === o
    o.__send__ :python_interpreter_update, status
  end
end