lib/rubypython.rb in rubypython-0.5.3 vs lib/rubypython.rb in rubypython-0.6.0

- old
+ new

@@ -13,43 +13,38 @@ # RubyPython.start # cPickle = RubyPython.import "cPickle" # puts cPickle.dumps("RubyPython is awesome!").rubify # RubyPython.stop module RubyPython - VERSION = '0.5.3' #:nodoc: - - # Do not load the FFI interface by default. Wait until the user asks for - # it. - @load_ffi = false - - # Indicates whether the \Python DLL has been loaded. For internal use - # only. - def self.load_ffi? #:nodoc: - @load_ffi - end + VERSION = '0.6.0' end require 'rubypython/blankobject' -require 'rubypython/options' +require 'rubypython/interpreter' require 'rubypython/python' require 'rubypython/pythonerror' require 'rubypython/pyobject' require 'rubypython/rubypyproxy' require 'rubypython/pymainclass' require 'rubypython/pygenerator' +require 'rubypython/tuple' +require 'thread' module RubyPython class << self - # Controls whether RubyPython is operating in <em>Normal Mode</em> or - # <em>Legacy Mode</em>. + ## + # :attr_accessor: + # Controls whether RubyPython is operating in <em>Proxy Mode</em> or + # <em>Legacy Mode</em>. This behavioural difference is deprecated as of + # RubyPython 0.6 and will be removed in a subsequent release. # - # === Normal Mode + # === Proxy Mode # By default, +legacy_mode+ is +false+, meaning that any object returned - # from a \Python function call will be wrapped in an instance of - # +RubyPyProxy+ or one of its subclasses. This allows \Python method - # calls to be forwarded to the \Python object, even if it would otherwise - # be a native Ruby object. + # from a \Python function call will be wrapped in a Ruby-Python proxy + # (an instance of +RubyPyProxy+ or one of its subclasses). This allows + # \Python method calls to be forwarded to the \Python object, even if it + # would otherwise be a native Ruby object. # # RubyPython.session do # string = RubyPython.import 'string' # ascii_letters = string.ascii_letters # puts ascii_letters.isalpha # => True @@ -58,23 +53,45 @@ # # === Legacy Mode # If +legacy_mode+ is +true+, RubyPython automatically tries to convert # returned objects to native Ruby object types. If there is no such # conversion, the object remains wrapped in +RubyPyProxy+. This - # behaviour is the same as RubyPython 0.2 and earlier. This mode is not - # recommended and may be phased out for RubyPython 1.0. + # behaviour is the same as RubyPython 0.2 and earlier. This mode is + # deprecated as of RubyPython 0.6 and will be removed. # # RubyPython.legacy_mode = true # RubyPython.session do # string = RubyPython.import 'string' # ascii_letters = string.ascii_letters # puts ascii_letters.isalpha # throws NoMethodError # end - attr_accessor :legacy_mode + def legacy_mode=(value) + warn_legacy_mode_deprecation unless defined? @legacy_mode + @legacy_mode = value + end - # Starts the \Python interpreter. Either +RubyPython.start+, - # +RubyPython.session+, or +RubyPython.run+ must be run before using any + def legacy_mode + unless defined? @legacy_mode + warn_legacy_mode_deprecation + @legacy_mode = nil + end + @legacy_mode + end + + def legacy_mode? + @legacy_mode = nil unless defined? @legacy_mode + @legacy_mode + end + private :legacy_mode? + + def warn_legacy_mode_deprecation + warn "RubyPython's Legacy Mode is deprecated and will be removed after version #{VERSION}." + end + private :warn_legacy_mode_deprecation + + ## 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. @@ -88,31 +105,34 @@ # With an alternative \Python executable: # RubyPython.start(:python_exe => 'python2.7') # 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. def start(options = {}) - RubyPython.configure(options) + Mutex.new.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 @load_ffi - @load_ffi = true - @reload = false - reload_library + unless defined? RubyPython::Python.ffi_libraries + Runtime.__send__(:infect!, RubyPython::Python) + end end return false if RubyPython::Python.Py_IsInitialized != 0 - - if @reload - reload_library - @reload = false - end - RubyPython::Python.Py_Initialize notify :start true end @@ -193,11 +213,11 @@ # # :call-seq: # run(options = {}) { block to execute in RubyPython context } def run(options = {}, &block) start(options) - module_eval(&block) + self.module_eval(&block) ensure stop end # Starts the \Python interpreter for a @@ -216,27 +236,32 @@ # 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. def start_from_virtualenv(virtualenv) result = start(:python_exe => File.join(virtualenv, "bin", "python")) - activate + activate_virtualenv result end - # Returns an object describing the currently active Python interpreter. + # Returns an object describing the active Python interpreter. Returns + # +nil+ if there is no active interpreter. def python - RubyPython::Python::EXEC + if self.const_defined? :Runtime + self::Runtime + else + nil + end end # Used to activate the virtualenv. - def activate + def activate_virtualenv imp = import("imp") imp.load_source("activate_this", - File.join(File.dirname(RubyPython::Python::EXEC.python), + File.join(File.dirname(RubyPython::Runtime.python), "activate_this.py")) end - private :activate + private :activate_virtualenv def add_observer(object) @observers ||= [] @observers << object true @@ -245,24 +270,13 @@ def notify(status) @observers ||= [] @observers.each do |o| next if nil === o - o.update status + o.__send__ :python_interpreter_update, status end end private :notify - - def reload_library - # Invalidate the current Python instance, if defined. - if defined? RubyPython::Python::EXEC and RubyPython::Python::EXEC - RubyPython::Python::EXEC.instance_eval { invalidate! } - end - remove_const :Python - load RubyPython::PYTHON_RB - true - end - private :reload_library end add_observer PyMain add_observer Operators add_observer PyObject::AutoPyPointer