Skip to content

Commit fd14ca1

Browse files
authored
Merge pull request #26 from mrkn/rewrite
Rewrite toward version 1.0
2 parents 3232c8d + 6a2ba40 commit fd14ca1

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

71 files changed

+5325
-2502
lines changed

.travis.yml

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,20 @@ rvm:
99
- 2.1.10
1010

1111
env:
12+
global:
13+
- PYCALL_DEBUG_FIND_LIBPYTHON=1
14+
matrix:
1215
- PYTHON=python
1316
- PYTHON=python3 LIBPYTHON=wrong_value
14-
- LIBPYTHON=/usr/lib/libpython3.2mu.so.1
17+
- LIBPYTHON=/opt/python/3.5.3/lib/libpython3.5m.so
1518

1619
addons:
1720
apt:
1821
packages:
1922
- python3
2023
- python3-dev
2124
- python3-all
25+
- python3-all-dev
2226

2327
before_install:
2428
- gem update --system
@@ -28,3 +32,10 @@ before_script:
2832
- bundle exec rake clobber compile
2933
- echo === python investigator.py ===
3034
- python lib/pycall/python/investigator.py
35+
- python3 lib/pycall/python/investigator.py
36+
- pip install numpy
37+
- pip3 install numpy
38+
39+
matrix:
40+
allow_failures:
41+
- env: PYTHON=python # Ignore failed on python 2.7

CHANGES.md

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# The change history of PyCall
2+
3+
## master
4+
5+
* Rewrite almost all fundamental parts of PyCall as C extension.
6+
7+
* PyCall now calls `Py_DecRef` in the finalizer of `PyCall::PyPtr`.
8+
9+
* Change the system of object mapping between Python and Ruby, drastically.
10+
Now PyCall does not have `PyObject` class for wrapper objects.
11+
Instead, PyCall generally makes `Object` instances and extends them by
12+
`PyObjectWrapper` module.
13+
But for Python module objects, PyCall makes anonymous `Module` instances
14+
that are extended by `PyObjectWrapper` module.
15+
Moreover for Python type objects, PyCall makes `Class` instances and extends
16+
them by `PyTypeObjectWrapper` module.
17+
18+
* Change `PyCall.eval` to be a wrapper of `__builtins__.eval` in Python.
19+
This means that `filename:` and `input_type:` parameters are dropped.
20+
Instead, two new parameters `globals:` and `locals:` are introduced.
21+
`globals:` is used for specifying a dictionary that is the global
22+
namespace referred by the evaluated expression.
23+
`locals:` is used for specifying a mapping object that is the local
24+
namespace referred by the evaluated expression.
25+
26+
* Add `PyCall.exec` for the replacement of the former `PyCall.eval`
27+
with `input_type: :file`.
28+
It has `globals:` and `locals:` parameters for the same meaning as
29+
the new `PyCall.eval` described above.
30+
31+
* Drop `PyCall.wrap_ruby_callable` and `PyCall.wrap_ruby_object` always
32+
craetes a callable Python object taht has an ID of the given Ruby object.

Gemfile

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,3 @@ source 'https://rubygems.org'
22

33
# Specify your gem's dependencies in pycall.gemspec
44
gemspec
5-
6-
group :development do
7-
gem 'guard-rspec', require: false
8-
gem 'terminal-notifier-guard', require: false
9-
end

Rakefile

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,29 @@
1-
require "bundler/gem_tasks"
2-
require "rspec/core/rake_task"
1+
require "bundler"
2+
Bundler::GemHelper.install_tasks
3+
4+
require "rake"
35
require "rake/extensiontask"
6+
require "rspec/core/rake_task"
47

58
Dir[File.expand_path('../tasks/**/*.rake', __FILE__)].each {|f| load f }
69

7-
Rake::ExtensionTask.new('pycall/pyptr')
10+
gem_spec = eval(File.read('pycall.gemspec'))
11+
Rake::ExtensionTask.new('pycall', gem_spec) do |ext|
12+
ext.lib_dir = File.join(*['lib', ENV['FAT_DIR']].compact)
13+
ext.cross_compile = true
14+
ext.cross_platform = %w[x86-mingw32 x64-mingw32]
15+
ext.cross_compiling do |s|
16+
s.files.concat %w[lib/2.2/pycall.so lib/2.3/pycall.so lib/2.4/pycall.so]
17+
end
18+
end
19+
20+
desc "Compile binaries for mingw platform using rake-compiler-dock"
21+
task 'build:mingw' do
22+
require 'rake_compiler_dock'
23+
RakeCompilerDock.sh "bundle && rake cross native gem RUBY_CC_VERSION=2.1.6:2.2.2:2.3.0:2.4.0"
24+
end
25+
826
RSpec::Core::RakeTask.new(:spec)
927

1028
task :default => :spec
29+
task spec: :compile

appveyor.yml

Lines changed: 8 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,6 @@ environment:
66
PYTHONDIR: "C:\\Python27"
77
PYTHON: "C:\\Python27\\python.exe"
88

9-
- ruby_version: "21"
10-
PYTHONDIR: "C:\\Python33"
11-
PYTHON: "C:\\Python33\\python.exe"
12-
139
- ruby_version: "21"
1410
PYTHONDIR: "C:\\Python34"
1511
PYTHON: "C:\\Python34\\python.exe"
@@ -27,10 +23,6 @@ environment:
2723
PYTHONDIR: "C:\\Python27-x64"
2824
PYTHON: "C:\\Python27-x64\\python.exe"
2925

30-
- ruby_version: "21-x64"
31-
PYTHONDIR: "C:\\Python33-x64"
32-
PYTHON: "C:\\Python33-x64\\python.exe"
33-
3426
- ruby_version: "21-x64"
3527
PYTHONDIR: "C:\\Python34-x64"
3628
PYTHON: "C:\\Python34-x64\\python.exe"
@@ -48,10 +40,6 @@ environment:
4840
PYTHONDIR: "C:\\Python27"
4941
PYTHON: "C:\\Python27\\python.exe"
5042

51-
- ruby_version: "22"
52-
PYTHONDIR: "C:\\Python33"
53-
PYTHON: "C:\\Python33\\python.exe"
54-
5543
- ruby_version: "22"
5644
PYTHONDIR: "C:\\Python34"
5745
PYTHON: "C:\\Python34\\python.exe"
@@ -69,10 +57,6 @@ environment:
6957
PYTHONDIR: "C:\\Python27-x64"
7058
PYTHON: "C:\\Python27-x64\\python.exe"
7159

72-
- ruby_version: "22-x64"
73-
PYTHONDIR: "C:\\Python33-x64"
74-
PYTHON: "C:\\Python33-x64\\python.exe"
75-
7660
- ruby_version: "22-x64"
7761
PYTHONDIR: "C:\\Python34-x64"
7862
PYTHON: "C:\\Python34-x64\\python.exe"
@@ -90,10 +74,6 @@ environment:
9074
PYTHONDIR: "C:\\Python27"
9175
PYTHON: "C:\\Python27\\python.exe"
9276

93-
- ruby_version: "23"
94-
PYTHONDIR: "C:\\Python33"
95-
PYTHON: "C:\\Python33\\python.exe"
96-
9777
- ruby_version: "23"
9878
PYTHONDIR: "C:\\Python34"
9979
PYTHON: "C:\\Python34\\python.exe"
@@ -111,10 +91,6 @@ environment:
11191
PYTHONDIR: "C:\\Python27-x64"
11292
PYTHON: "C:\\Python27-x64\\python.exe"
11393

114-
- ruby_version: "23-x64"
115-
PYTHONDIR: "C:\\Python33-x64"
116-
PYTHON: "C:\\Python33-x64\\python.exe"
117-
11894
- ruby_version: "23-x64"
11995
PYTHONDIR: "C:\\Python34-x64"
12096
PYTHON: "C:\\Python34-x64\\python.exe"
@@ -144,13 +120,19 @@ build: off
144120
install:
145121
- "SET PATH=%PYTHONDIR%;%PYTHONDIR%\\Scripts;%PATH%"
146122
- "SET PATH=C:\\Ruby%ruby_version%\\bin;%PATH%"
147-
- bundle install
123+
- "bundle install"
124+
- "pip install numpy"
148125

149126
before_test:
150127
- "bundle exec rake -rdevkit clobber compile"
151128
- ECHO "=== python investigator.py ==="
152129
- "python lib\\pycall\\python\\investigator.py"
153130

154131
test_script:
155-
- "SET DEBUG_FIND_LIBPYTHON=1"
132+
- "SET PYCALL_DEBUG_FIND_LIBPYTHON=1"
156133
- rake
134+
135+
matrix:
136+
allow_failures:
137+
- PYTHONDIR: "C:\\Python27"
138+
- PYTHONDIR: "C:\\Python27-x64"

examples/classifier_comparison.rb

Lines changed: 52 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -34,102 +34,102 @@
3434
]
3535

3636
classifiers = [
37-
KNeighborsClassifier.(3),
38-
SVC.(kernel: 'linear', C: 0.025),
39-
SVC.(gamma: 2, C: 1),
40-
DecisionTreeClassifier.(max_depth: 5),
41-
RandomForestClassifier.(max_depth: 5, n_estimators: 10, max_features: 1),
42-
AdaBoostClassifier.(),
43-
GaussianNB.(),
44-
LinearDiscriminantAnalysis.(),
45-
QuadraticDiscriminantAnalysis.()
37+
KNeighborsClassifier.new(3),
38+
SVC.new(kernel: 'linear', C: 0.025),
39+
SVC.new(gamma: 2, C: 1),
40+
DecisionTreeClassifier.new(max_depth: 5),
41+
RandomForestClassifier.new(max_depth: 5, n_estimators: 10, max_features: 1),
42+
AdaBoostClassifier.new(),
43+
GaussianNB.new(),
44+
LinearDiscriminantAnalysis.new(),
45+
QuadraticDiscriminantAnalysis.new()
4646
]
4747

48-
x, y = make_classification.(
48+
x, y = *make_classification(
4949
n_features: 2,
5050
n_redundant: 0,
5151
n_informative: 2,
5252
random_state: 1,
5353
n_clusters_per_class: 1
5454
)
5555

56-
np.random.seed.(42)
57-
x += 2 * np.random.random_sample.(x.shape)
58-
linearly_separable = PyCall.tuple(x, y)
56+
np.random.seed(42)
57+
x += 2 * np.random.random_sample(x.shape)
58+
linearly_separable = PyCall.tuple([x, y]) # FIXME: allow PyCall.tuple(x, y)
5959

6060
datasets = [
61-
make_moons.(noise: 0.3, random_state: 0),
62-
make_circles.(noise: 0.2, factor: 0.5, random_state: 1),
61+
make_moons(noise: 0.3, random_state: 0),
62+
make_circles(noise: 0.2, factor: 0.5, random_state: 1),
6363
linearly_separable
6464
]
6565

66-
fig = plt.figure.(figsize: PyCall.tuple(27, 9))
66+
fig = plt.figure(figsize: [27, 9])
6767
i = 1
68-
all = PyCall.slice(nil)
68+
all = PyCall::Slice.all
6969
datasets.each do |ds|
70-
x, y = ds
71-
x = StandardScaler.().fit_transform.(x)
72-
x_train, x_test, y_train, y_test = train_test_split.(x, y, test_size: 0.4)
70+
x, y = *ds
71+
x = StandardScaler.new.fit_transform(x)
72+
x_train, x_test, y_train, y_test = train_test_split(x, y, test_size: 0.4)
7373

74-
x_min, x_max = np.min.(x[all, 0]) - 0.5, np.max.(x[all, 0]) + 0.5
75-
y_min, y_max = np.min.(x[all, 1]) - 0.5, np.max.(x[all, 1]) + 0.5
74+
x_min, x_max = np.min(x[all, 0]) - 0.5, np.max(x[all, 0]) + 0.5
75+
y_min, y_max = np.min(x[all, 1]) - 0.5, np.max(x[all, 1]) + 0.5
7676

77-
xx, yy = np.meshgrid.(
78-
np.linspace.(x_min, x_max, ((x_max - x_min)/h).round),
79-
np.linspace.(y_min, y_max, ((y_max - y_min)/h).round),
77+
xx, yy = np.meshgrid(
78+
np.linspace(x_min, x_max, ((x_max - x_min)/h).round),
79+
np.linspace(y_min, y_max, ((y_max - y_min)/h).round),
8080
)
81-
mesh_points = np.dstack.(PyCall.tuple(xx.ravel.(), yy.ravel.()))[0, all, all]
81+
mesh_points = np.dstack(PyCall.tuple([xx.ravel(), yy.ravel()]))[0, all, all]
8282

8383
# just plot the dataset first
84-
cm = plt.cm.RdBu
85-
cm_bright = mplc.ListedColormap.(["#FF0000", "#0000FF"])
86-
ax = plt.subplot.(datasets.length, classifiers.length + 1, i)
84+
cm = plt.cm.__dict__[:RdBu]
85+
cm_bright = mplc.ListedColormap.new(["#FF0000", "#0000FF"])
86+
ax = plt.subplot(datasets.length, classifiers.length + 1, i)
8787
# plot the training points
88-
ax.scatter.(x_train[all, 0], x_train[all, 1], c: y_train, cmap: cm_bright)
88+
ax.scatter(x_train[all, 0], x_train[all, 1], c: y_train, cmap: cm_bright)
8989
# and testing points
90-
ax.scatter.(x_test[all, 0], x_test[all, 1], c: y_test, cmap: cm_bright, alpha: 0.6)
90+
ax.scatter(x_test[all, 0], x_test[all, 1], c: y_test, cmap: cm_bright, alpha: 0.6)
9191

92-
ax.set_xlim.(np.min.(xx), np.max.(xx))
93-
ax.set_ylim.(np.min.(yy), np.max.(yy))
94-
ax.set_xticks.(PyCall.tuple())
95-
ax.set_yticks.(PyCall.tuple())
92+
ax.set_xlim(np.min(xx), np.max(xx))
93+
ax.set_ylim(np.min(yy), np.max(yy))
94+
ax.set_xticks(PyCall.tuple())
95+
ax.set_yticks(PyCall.tuple())
9696
i += 1
9797

9898
# iterate over classifiers
9999
names.zip(classifiers).each do |name, clf|
100-
ax = plt.subplot.(datasets.length, classifiers.length + 1, i)
101-
clf.fit.(x_train, y_train)
102-
scor = clf.score.(x_test, y_test)
100+
ax = plt.subplot(datasets.length, classifiers.length + 1, i)
101+
clf.fit(x_train, y_train)
102+
scor = clf.score(x_test, y_test)
103103

104104
# Plot the decision boundary. For that, we will assign a color to each
105105
# point in the mesh [x_min, x_max]x[y_min, y_max]
106106
begin
107107
# not implemented for some
108-
z = clf.decision_function.(mesh_points)
108+
z = clf.decision_function(mesh_points)
109109
rescue
110-
z = clf.predict_proba.(mesh_points)[all, 1]
110+
z = clf.predict_proba(mesh_points)[all, 1]
111111
end
112112

113113
# Put the result into a color plot
114-
z = z.reshape.(xx.shape)
115-
ax.contourf.(xx, yy, z, cmap: cm, alpha: 0.8)
114+
z = z.reshape(xx.shape)
115+
ax.contourf(xx, yy, z, cmap: cm, alpha: 0.8)
116116

117117
# Plot also the training points
118-
ax.scatter.(x_train[all, 0], x_train[all, 1], c: y_train, cmap: cm_bright)
118+
ax.scatter(x_train[all, 0], x_train[all, 1], c: y_train, cmap: cm_bright)
119119
# and testing points
120-
ax.scatter.(x_test[all, 0], x_test[all, 1], c: y_test, cmap: cm_bright, alpha: 0.6)
120+
ax.scatter(x_test[all, 0], x_test[all, 1], c: y_test, cmap: cm_bright, alpha: 0.6)
121121

122-
ax.set_xlim.(np.min.(xx), np.max.(xx))
123-
ax.set_ylim.(np.min.(yy), np.max.(yy))
124-
ax.set_xticks.(PyCall.tuple())
125-
ax.set_yticks.(PyCall.tuple())
126-
ax.set_title.(name)
122+
ax.set_xlim(np.min(xx), np.max(xx))
123+
ax.set_ylim(np.min(yy), np.max(yy))
124+
ax.set_xticks(PyCall.tuple())
125+
ax.set_yticks(PyCall.tuple())
126+
ax.set_title(name)
127127

128-
ax.text.(np.max.(xx) - 0.3, np.min.(yy) + 0.3, "%.2f" % scor, size: 15, horizontalalignment: 'right')
128+
ax.text(np.max(xx) - 0.3, np.min(yy) + 0.3, "%.2f" % scor, size: 15, horizontalalignment: 'right')
129129

130130
i += 1
131131
end
132132
end
133133

134-
fig.subplots_adjust.(left: 0.02, right: 0.98)
135-
plt.show.()
134+
fig.subplots_adjust(left: 0.02, right: 0.98)
135+
plt.show()

examples/hist.rb

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -10,23 +10,23 @@
1010
pyimport 'matplotlib.mlab', as: 'mlab'
1111
pyimport 'matplotlib.pyplot', as: 'plt'
1212

13-
np.random.seed.(0)
13+
np.random.seed(0)
1414

1515
mu = 100
1616
sigma = 15
17-
x = mu + sigma * np.random.randn.(437)
17+
x = mu + sigma * np.random.randn(437)
1818

1919
num_bins = 50
2020

21-
fig, ax = plt.subplots.()
21+
fig, ax = *plt.subplots
2222

23-
n, bins, patches = ax.hist.(x, num_bins, normed: 1)
23+
n, bins, patches = *ax.hist(x, num_bins, normed: 1)
2424

25-
y = mlab.normpdf.(bins, mu, sigma)
26-
ax.plot.(bins, y, '--')
27-
ax.set_xlabel.('Smarts')
28-
ax.set_ylabel.('Probability density')
29-
ax.set_title.('Histogram of IQ: $\mu=100$, $\sigma=15$')
25+
y = mlab.normpdf(bins, mu, sigma)
26+
ax.plot(bins, y, '--')
27+
ax.set_xlabel('Smarts')
28+
ax.set_ylabel('Probability density')
29+
ax.set_title('Histogram of IQ: $\mu=100$, $\sigma=15$')
3030

31-
fig.tight_layout.()
32-
plt.show.()
31+
fig.tight_layout()
32+
plt.show()

0 commit comments

Comments
 (0)