pycall 1.2.1 → 1.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/lib/pycall/list.rb CHANGED
@@ -13,9 +13,9 @@ module PyCall
13
13
  PyCall.len(self)
14
14
  end
15
15
 
16
- def each
16
+ def each(&block)
17
17
  return enum_for unless block_given?
18
- LibPython::Helpers.sequence_each(__pyptr__, &proc)
18
+ LibPython::Helpers.sequence_each(__pyptr__, &block)
19
19
  self
20
20
  end
21
21
 
@@ -178,7 +178,7 @@ module PyCall
178
178
  def check_isclass(pyptr)
179
179
  pyptr = pyptr.__pyptr__ if pyptr.kind_of? PyObjectWrapper
180
180
  return if pyptr.kind_of? LibPython::API::PyType_Type
181
- return defined?(LibPython::API::PyClass_Type) && pyptr.kind_of?(LibPython::API::PyClass_Type)
181
+ return if defined?(LibPython::API::PyClass_Type) && pyptr.kind_of?(LibPython::API::PyClass_Type)
182
182
  raise TypeError, "PyType object is required"
183
183
  end
184
184
  end
@@ -1,12 +1,85 @@
1
- from distutils.sysconfig import get_config_var
1
+ #!/usr/bin/env python
2
+
3
+ import ctypes.util
4
+ from distutils.sysconfig import get_config_var, get_python_version
5
+ import os
2
6
  import sys
3
7
 
4
- def conda():
5
- return 'conda' in sys.version or 'Continuum' in sys.version
8
+ is_windows = os.name == "nt"
9
+
10
+ def linked_libpython():
11
+ if is_windows:
12
+ return _linked_libpython_windows()
13
+ return _linked_libpython_unix()
14
+
15
+ class Dl_info(ctypes.Structure):
16
+ _fields_ = [
17
+ ("dli_fname", ctypes.c_char_p),
18
+ ("dli_fbase", ctypes.c_void_p),
19
+ ("dli_sname", ctypes.c_char_p),
20
+ ("dli_saddr", ctypes.c_void_p),
21
+ ]
22
+
23
+ def _linked_libpython_unix():
24
+ libdl = ctypes.CDLL(ctypes.util.find_library("dl"))
25
+ libdl.dladdr.argtypes = [ctypes.c_void_p, ctypes.POINTER(Dl_info)]
26
+ libdl.dladdr.restype = ctypes.c_int
27
+
28
+ dlinfo = Dl_info()
29
+ retcode = libdl.dladdr(
30
+ ctypes.cast(ctypes.pythonapi.Py_GetVersion, ctypes.c_void_p),
31
+ ctypes.pointer(dlinfo))
32
+ if retcode == 0: # means error
33
+ return None
34
+ path = os.path.realpath(dlinfo.dli_fname.decode())
35
+ if path == os.path.realpath(sys.executable):
36
+ return None
37
+ return path
38
+
39
+ def _linked_libpython_windows():
40
+ # Based on: https://stackoverflow.com/a/16659821
41
+ from ctypes.wintypes import HANDLE, LPWSTR, DWORD
42
+
43
+ GetModuleFileName = ctypes.windll.kernel32.GetModuleFileNameW
44
+ GetModuleFileName.argtypes = [HANDLE, LPWSTR, DWORD]
45
+ GetModuleFileName.restype = DWORD
46
+
47
+ MAX_PATH = 260
48
+ try:
49
+ buf = ctypes.create_unicode_buffer(MAX_PATH)
50
+ GetModuleFileName(ctypes.pythonapi._handle, buf, MAX_PATH)
51
+ return buf.value
52
+ except (ValueError, OSError):
53
+ return None
54
+
55
+ print("linked_libpython: {val}".format(val=(linked_libpython() or "None")))
56
+
57
+ sys_keys = [ "executable", "exec_prefix", "prefix" ]
58
+
59
+ for var in sys_keys:
60
+ print("{var}: {val}".format(var=var, val=(getattr(sys, var) or "None")))
61
+
62
+ config_keys = [ "INSTSONAME", "LIBDIR", "LIBPL", "LIBRARY", "LDLIBRARY",
63
+ "MULTIARCH", "PYTHONFRAMEWORKPREFIX", "SHLIB_SUFFIX", "srcdir" ]
64
+
65
+ for var in config_keys:
66
+ print("{var}: {val}".format(var=var, val=(get_config_var(var) or "None")))
67
+
68
+ print("ABIFLAGS: {val}".format(val=get_config_var("ABIFLAGS") or get_config_var("abiflags") or "None"))
69
+
70
+ version = get_python_version() or \
71
+ "{v.major}.{v.minor}".format(v=sys.version_info) or \
72
+ get_config_var("VERSION")
73
+ print("VERSION: {val}".format(val=version))
6
74
 
7
- for var in ('executable', 'exec_prefix', 'prefix'):
8
- print(var + ': ' + str(getattr(sys, var)))
9
- print('conda: ' + ('true' if conda() else 'false'))
10
- print('multiarch: ' + str(getattr(getattr(sys, 'implementation', sys), '_multiarch', None)))
11
- for var in ('VERSION', 'INSTSONAME', 'LIBRARY', 'LDLIBRARY', 'LIBDIR', 'PYTHONFRAMEWORKPREFIX', 'MULTIARCH'):
12
- print(var + ': ' + str(get_config_var(var)))
75
+ if is_windows:
76
+ if hasattr(sys, "base_exec_prefix"):
77
+ PYTHONHOME = sys.base_exec_prefix
78
+ else:
79
+ PYTHONHOME = sys.exec_prefix
80
+ else:
81
+ if hasattr(sys, "base_exec_prefix"):
82
+ PYTHONHOME = ":".join([sys.base_prefix, sys.base_exec_prefix])
83
+ else:
84
+ PYTHONHOME = ":".join([sys.prefix, sys.exec_prefix])
85
+ print("PYTHONHOME: {val}".format(val=PYTHONHOME))
@@ -51,8 +51,18 @@ module PyCall
51
51
 
52
52
  def <(other)
53
53
  case other
54
+ when self
55
+ false
54
56
  when PyTypeObjectWrapper
55
57
  __pyptr__ < other.__pyptr__
58
+ when Class
59
+ false if other.ancestors.include?(self)
60
+ when Module
61
+ if ancestors.include?(other)
62
+ true
63
+ elsif other.ancestors.include?(self)
64
+ false
65
+ end
56
66
  else
57
67
  raise TypeError, "compared with non class/module"
58
68
  end
@@ -1,3 +1,9 @@
1
1
  module PyCall
2
- VERSION = "1.2.1"
2
+ VERSION = "1.4.1"
3
+
4
+ module Version
5
+ numbers, TAG = VERSION.split("-")
6
+ MAJOR, MINOR, MICRO = numbers.split(".").map(&:to_i)
7
+ STRING = VERSION
8
+ end
3
9
  end
@@ -1,5 +1,54 @@
1
1
  module PyCall
2
2
  class WrapperObjectCache
3
+
4
+ begin
5
+ ObjectSpace::WeakMap.new[42] = Object.new
6
+ rescue
7
+ WMAP_SUPPORT_INT_KEY = false
8
+ else
9
+ case RUBY_PLATFORM
10
+ when /cygwin/, /mingw/, /mswin/
11
+ WMAP_SUPPORT_INT_KEY = false
12
+ else
13
+ WMAP_SUPPORT_INT_KEY = true
14
+ end
15
+ end
16
+
17
+ if WMAP_SUPPORT_INT_KEY
18
+ def self.get_key(pyptr)
19
+ pyptr.__address__
20
+ end
21
+ else
22
+ class Key
23
+ @address_key_map = {}
24
+
25
+ def self.[](address)
26
+ # An instance of Key created here is parmanently cached in @address_key_map.
27
+ # This behavior is intentional.
28
+ @address_key_map[address] ||= new(address)
29
+ end
30
+
31
+ def initialize(address)
32
+ @address = address
33
+ end
34
+
35
+ attr_reader :address
36
+
37
+ def ==(other)
38
+ case other
39
+ when Key
40
+ self.address == other.address
41
+ else
42
+ super
43
+ end
44
+ end
45
+ end
46
+
47
+ def self.get_key(pyptr)
48
+ Key[pyptr.__address__]
49
+ end
50
+ end
51
+
3
52
  def initialize(*restricted_pytypes)
4
53
  unless restricted_pytypes.empty?
5
54
  restricted_pytypes.each do |pytype|
@@ -8,9 +57,7 @@ module PyCall
8
57
  end
9
58
  end
10
59
  @restricted_pytypes = restricted_pytypes
11
- @wrapper_object_table = {}
12
- @wrapped_pyptr_table = {}
13
- @weakref_table = {}
60
+ @wrapper_object_table = ObjectSpace::WeakMap.new
14
61
  end
15
62
 
16
63
  def lookup(pyptr)
@@ -25,16 +72,14 @@ module PyCall
25
72
  end
26
73
  end
27
74
 
28
- wrapper_object_id = @wrapper_object_table[pyptr.__address__]
29
- if wrapper_object_id
30
- wrapper_object = ObjectSpace._id2ref(wrapper_object_id) rescue nil
31
- return wrapper_object if wrapper_object
75
+ key = self.class.get_key(pyptr)
76
+ wrapper_object = @wrapper_object_table[key]
77
+ unless wrapper_object
78
+ wrapper_object = yield(pyptr)
79
+ check_wrapper_object(wrapper_object)
80
+ @wrapper_object_table[key] = wrapper_object
32
81
  end
33
82
 
34
- wrapper_object = yield(pyptr)
35
- check_wrapper_object(wrapper_object)
36
- register_wrapper_object(pyptr, wrapper_object)
37
-
38
83
  wrapper_object
39
84
  end
40
85
 
@@ -43,19 +88,5 @@ module PyCall
43
88
  raise TypeError, "unexpected wrapper object (expected an object extended by PyObjectWrapper)"
44
89
  end
45
90
  end
46
-
47
- def register_wrapper_object(pyptr, wrapper_object)
48
- @wrapper_object_table[pyptr.__address__] = wrapper_object.__id__
49
- @wrapped_pyptr_table[wrapper_object.__id__] = pyptr.__address__
50
- ObjectSpace.define_finalizer(wrapper_object, &method(:unregister_wrapper_object))
51
- # TODO: weakref
52
- self
53
- end
54
-
55
- def unregister_wrapper_object(wrapper_object_id)
56
- pyptr_addr = @wrapped_pyptr_table.delete(wrapper_object_id)
57
- @wrapper_object_table.delete(pyptr_addr) if pyptr_addr
58
- self
59
- end
60
91
  end
61
92
  end
data/pycall.gemspec CHANGED
@@ -5,7 +5,13 @@ require 'pycall/version'
5
5
 
6
6
  Gem::Specification.new do |spec|
7
7
  spec.name = "pycall"
8
- spec.version = PyCall::VERSION
8
+ version_components = [
9
+ PyCall::Version::MAJOR.to_s,
10
+ PyCall::Version::MINOR.to_s,
11
+ PyCall::Version::MICRO.to_s,
12
+ PyCall::Version::TAG,
13
+ ]
14
+ spec.version = version_components.compact.join(".")
9
15
  spec.authors = ["Kenta Murata"]
10
16
  spec.email = ["mrkn@mrkn.jp"]
11
17
 
@@ -30,7 +36,7 @@ Gem::Specification.new do |spec|
30
36
  spec.require_paths = ["lib"]
31
37
  spec.extensions = ["ext/pycall/extconf.rb"]
32
38
 
33
- spec.add_development_dependency "bundler", ">= 1.17.2"
39
+ spec.add_development_dependency "bundler"
34
40
  spec.add_development_dependency "rake"
35
41
  spec.add_development_dependency "rake-compiler"
36
42
  spec.add_development_dependency "rake-compiler-dock"
@@ -38,4 +44,5 @@ Gem::Specification.new do |spec|
38
44
  spec.add_development_dependency "launchy"
39
45
  spec.add_development_dependency "pry"
40
46
  spec.add_development_dependency "pry-byebug"
47
+ spec.add_development_dependency "test-unit"
41
48
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pycall
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.1
4
+ version: 1.4.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kenta Murata
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-02-19 00:00:00.000000000 Z
11
+ date: 2021-07-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: 1.17.2
19
+ version: '0'
20
20
  type: :development
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
- version: 1.17.2
26
+ version: '0'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: rake
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -122,6 +122,20 @@ dependencies:
122
122
  - - ">="
123
123
  - !ruby/object:Gem::Version
124
124
  version: '0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: test-unit
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
125
139
  description: pycall
126
140
  email:
127
141
  - mrkn@mrkn.jp
@@ -130,15 +144,15 @@ extensions:
130
144
  - ext/pycall/extconf.rb
131
145
  extra_rdoc_files: []
132
146
  files:
147
+ - ".github/workflows/ci.yml"
148
+ - ".github/workflows/windows.yml"
133
149
  - ".gitignore"
134
150
  - ".rspec"
135
- - ".travis.yml"
136
151
  - CHANGES.md
137
152
  - Gemfile
138
153
  - LICENSE.txt
139
154
  - README.md
140
155
  - Rakefile
141
- - appveyor.yml
142
156
  - bin/console
143
157
  - bin/guard
144
158
  - bin/rspec
@@ -157,6 +171,7 @@ files:
157
171
  - examples/notebooks/classifier_comparison.ipynb
158
172
  - examples/notebooks/forest_importances.ipynb
159
173
  - examples/notebooks/iruby_integration.ipynb
174
+ - examples/notebooks/leaflet.ipynb
160
175
  - examples/notebooks/lorenz_attractor.ipynb
161
176
  - examples/notebooks/polar_axes.ipynb
162
177
  - examples/notebooks/sum_benchmarking.ipynb
@@ -171,6 +186,7 @@ files:
171
186
  - ext/pycall/pycall_internal.h
172
187
  - ext/pycall/range.c
173
188
  - ext/pycall/ruby_wrapper.c
189
+ - ext/pycall/thread.c
174
190
  - images/pycallrb_logo.png
175
191
  - images/pycallrb_logo_200.png
176
192
  - lib/pycall.rb
@@ -180,6 +196,7 @@ files:
180
196
  - lib/pycall/import.rb
181
197
  - lib/pycall/init.rb
182
198
  - lib/pycall/iruby_helper.rb
199
+ - lib/pycall/iterable_wrapper.rb
183
200
  - lib/pycall/libpython.rb
184
201
  - lib/pycall/libpython/finder.rb
185
202
  - lib/pycall/libpython/pyobject_struct.rb
@@ -219,7 +236,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
219
236
  - !ruby/object:Gem::Version
220
237
  version: '0'
221
238
  requirements: []
222
- rubygems_version: 3.0.2
239
+ rubygems_version: 3.2.21
223
240
  signing_key:
224
241
  specification_version: 4
225
242
  summary: pycall
data/.travis.yml DELETED
@@ -1,56 +0,0 @@
1
- language: ruby
2
-
3
- os: linux
4
-
5
- dist: trusty
6
- sudo: required
7
-
8
- rvm:
9
- - ruby-head
10
- - 2.5.0
11
- - 2.4.3
12
- - 2.3.5
13
-
14
- env:
15
- global:
16
- - PYCALL_DEBUG_FIND_LIBPYTHON=1
17
- matrix:
18
- - PYENV_VERSION=2.7.13
19
- - PYENV_VERSION=3.6.2
20
- - PYENV_VERSION=system LIBPYTHON=versions/3.6.2/lib/libpython3.6m.so
21
- - PYENV_VERSION=miniconda2-4.1.11
22
- - PYENV_VERSION=miniconda3-4.3.11
23
-
24
- matrix:
25
- include:
26
- - os: osx
27
- osx_image: xcode9
28
- compiler: clang
29
- rvm: 2.4.1
30
- env: PYENV_VERSION=3.6.2
31
- - os: osx
32
- osx_image: xcode9
33
- compiler: clang
34
- rvm: 2.4.1
35
- env: PYENV_VERSION=system LIBPYTHON=versions/3.6.2/lib/libpython3.6m.so
36
- - os: osx
37
- osx_image: xcode9
38
- compiler: clang
39
- rvm: 2.4.1
40
- env: PYENV_VERSION=miniconda3-4.3.11
41
- allow_failures:
42
- - os: osx
43
-
44
- before_install:
45
- - gem update --system
46
- - gem update bundler
47
- - export PATH="$(pyenv root)/bin:$PATH"
48
- - eval "$(pyenv init -)"
49
-
50
- install:
51
- - ci/travis_install.sh
52
-
53
- before_script:
54
- - . ci/travis_before_script.sh
55
- - bundle exec rake clobber compile
56
- - python lib/pycall/python/investigator.py