pycall 1.2.0 → 1.4.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6f0a9785eaac83c23c7c49f7cf48b5f5fd658e8d6b1a1f3dc36f1b9039d6747c
4
- data.tar.gz: 9e1996633c503014e3110242c242d4590ad7fa2061ebadea9f856875eff48f76
3
+ metadata.gz: 79fa29a4fd735c0741f03e74aadce297273cd2d64c0813b9ee2e20ad5fa321b9
4
+ data.tar.gz: 108942ac4b4d45324644fe90af4e56e239f7ce3b2f27fa0d98d5defa439da8db
5
5
  SHA512:
6
- metadata.gz: 8b358c6af0013f068da55247fb45ddc24d9f00d0e8826c55530bd39d0f9d16cbc04390695f6b9e0c4518beefbbb396cf4eeb80bc46089dc0132ff3ed763d8cfd
7
- data.tar.gz: 9576c22da8b097a52577d4a82065384db2ea2d8878fc2012b90f7350b1a4db05e6892242a23c36ebe78f0ebe36ca6b38ad270c33277a7760761f0f4f9cffdebf
6
+ metadata.gz: eb899c3e9c353622945df3b816df4588cd3b4606f723c53973a2f8d77d8eb9edf94b7dbcf15ff4d33f65430fd6d38a8bc2ccc2fda2a1f8f274dc769b0280e42a
7
+ data.tar.gz: ff84eb82b4e10d1a2f699abd32cfcdcc6159cba6b83f2258bc4100c7229bb49ca1c7593b5a6629ef2081007728bc3be5e266b65c2967c49c043fb3dfe0bf3835
@@ -0,0 +1,150 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches:
6
+ - master
7
+ - "check/ci/**"
8
+ - "check/unix/**"
9
+ pull_request:
10
+ types:
11
+ - opened
12
+ - synchronize
13
+ - reopened
14
+
15
+ jobs:
16
+ test:
17
+ name: ${{ matrix.venv }}${{ matrix.os }}/${{ matrix.ruby }}/${{ matrix.python }}-${{ matrix.python_architecture }}
18
+ runs-on: ${{ matrix.os }}
19
+
20
+ strategy:
21
+ fail-fast: false
22
+ matrix:
23
+ os:
24
+ - ubuntu-20.04
25
+ - macos-latest
26
+ ruby:
27
+ - "3.0"
28
+ - 2.7
29
+ - 2.6
30
+ python:
31
+ - 3.x
32
+ - 2.x
33
+ python_architecture:
34
+ - x64
35
+ venv:
36
+ - ""
37
+ include:
38
+ - { os: ubuntu-20.04 , ruby: 2.5 , python: 3.x , python_architecture: x64 , venv: "" }
39
+ - { os: ubuntu-20.04 , ruby: 2.4 , python: 3.x , python_architecture: x64 , venv: "" }
40
+ - { os: ubuntu-20.04 , ruby: 2.5 , python: 2.x , python_architecture: x64 , venv: "" }
41
+ - { os: ubuntu-20.04 , ruby: 2.4 , python: 2.x , python_architecture: x64 , venv: "" }
42
+ - { os: ubuntu-20.04 , ruby: 2.7 , python: 3.8 , python_architecture: x64 , venv: "" }
43
+ - { os: ubuntu-20.04 , ruby: 2.7 , python: 3.7 , python_architecture: x64 , venv: "" }
44
+ - { os: ubuntu-20.04 , ruby: 2.7 , python: 3.6 , python_architecture: x64 , venv: "" }
45
+ - { os: ubuntu-18.04 , ruby: 2.7 , python: 3.8 , python_architecture: x64 , venv: "" }
46
+ - { os: ubuntu-20.04 , ruby: debug , python: 3.x , python_architecture: x64 , venv: "" }
47
+ - { os: ubuntu-20.04 , ruby: "3.0" , python: 3.x , python_architecture: x64 , venv: "venv:" }
48
+ - { os: ubuntu-18.04 , ruby: "3.0" , python: 3.x , python_architecture: x64 , venv: "venv:" }
49
+ - { os: ubuntu-18.04 , ruby: "3.0" , python: 3.8 , python_architecture: x64 , venv: "venv:" }
50
+ - { os: macos-latest , ruby: "3.0" , python: 3.x , python_architecture: x64 , venv: "venv:" }
51
+ - { os: macos-latest , ruby: "3.0" , python: 3.8 , python_architecture: x64 , venv: "venv:" }
52
+ #- { os: macos-latest , ruby: debug , python: 3.x , python_architecture: x64 , venv: "" }
53
+
54
+ steps:
55
+ - uses: actions/checkout@v2
56
+ with:
57
+ fetch-depth: 1
58
+
59
+ - uses: ruby/setup-ruby@v1
60
+ if: matrix.ruby_version != 'master-nightly'
61
+ with:
62
+ ruby-version: ${{ matrix.ruby }}
63
+
64
+ - uses: actions/setup-python@v2
65
+ with:
66
+ python-version: ${{ matrix.python }}
67
+ architecture: ${{ matrix.python_architecture }}
68
+
69
+ - run: pip install --user numpy
70
+
71
+ - run: bundle install
72
+
73
+ - run: rake compile
74
+
75
+ - run: python lib/pycall/python/investigator.py
76
+
77
+ - name: venv examination
78
+ run: |
79
+ python -m venv ~/test-venv
80
+ source ~/test-venv/bin/activate
81
+ ruby -Ilib -Iext/pycall -rpycall -ePyCall.builtins
82
+ env:
83
+ PYCALL_DEBUG_FIND_LIBPYTHON: 1
84
+ if: ${{ matrix.venv != '' }}
85
+
86
+ - run: rake
87
+ env:
88
+ PYTHON: python
89
+
90
+ conda:
91
+ name: conda:${{ matrix.os }}/${{ matrix. ruby }}/${{ matrix.python }}
92
+ runs-on: ${{ matrix.os }}
93
+
94
+ strategy:
95
+ fail-fast: false
96
+ matrix:
97
+ os:
98
+ - ubuntu-20.04
99
+ - macos-latest
100
+ ruby:
101
+ - "3.0"
102
+ python:
103
+ - 3.8
104
+
105
+ steps:
106
+ - uses: actions/checkout@v2
107
+ with:
108
+ fetch-depth: 1
109
+
110
+ - uses: conda-incubator/setup-miniconda@v2
111
+ with:
112
+ activate-environment: test
113
+ python-version: ${{ matrix.python }}
114
+
115
+ - uses: ruby/setup-ruby@v1
116
+ if: matrix.ruby_version != 'master-nightly'
117
+ with:
118
+ ruby-version: ${{ matrix.ruby }}
119
+
120
+ - name: Add Ruby path
121
+ run: |
122
+ echo >> ~/.profile
123
+ echo >> ~/.profile
124
+ IFS=:
125
+ for p in $PATH; do
126
+ case $p in
127
+ */Ruby/*)
128
+ echo "export PATH=$p:\$PATH" >> ~/.profile
129
+ ;;
130
+ esac
131
+ done
132
+
133
+ - run: cat ~/.profile
134
+
135
+ - run: bash -xe ~/.profile
136
+
137
+ - run: conda install numpy
138
+ shell: bash -l {0}
139
+
140
+ - run: bundle install
141
+
142
+ - run: rake compile
143
+
144
+ - run: python lib/pycall/python/investigator.py
145
+ shell: bash -l {0}
146
+
147
+ - run: rake
148
+ env:
149
+ PYTHON: python
150
+ shell: bash -l {0}
@@ -0,0 +1,127 @@
1
+ name: Windows
2
+
3
+ on:
4
+ push:
5
+ branches:
6
+ - master
7
+ - "check/ci/**"
8
+ - "check/windows/**"
9
+ pull_request:
10
+ types:
11
+ - opened
12
+ - synchronize
13
+ - reopened
14
+
15
+ jobs:
16
+ test:
17
+ name: ruby-${{ matrix.ruby }}/python-${{ matrix.python }}-${{ matrix.python_architecture }}
18
+ runs-on: windows-latest
19
+
20
+ strategy:
21
+ fail-fast: false
22
+ matrix:
23
+ ruby:
24
+ - "3.0"
25
+ - 2.7
26
+ - 2.6
27
+ python:
28
+ - 3.x
29
+ - 2.x
30
+ python_architecture:
31
+ - x64
32
+ include:
33
+ - { os: windows-latest , ruby: mingw , python: 3.x , python_architecture: x64 }
34
+ #- { os: windows-latest , ruby: mswin , python: 3.x , python_architecture: x64 }
35
+
36
+ steps:
37
+ - uses: actions/checkout@v2
38
+ with:
39
+ fetch-depth: 1
40
+
41
+ - uses: ruby/setup-ruby@v1
42
+ if: matrix.ruby_version != 'master-nightly'
43
+ with:
44
+ ruby-version: ${{ matrix.ruby }}
45
+
46
+ - uses: actions/setup-python@v2
47
+ with:
48
+ python-version: ${{ matrix.python }}
49
+ architecture: ${{ matrix.python_architecture }}
50
+
51
+ - run: pip install --user numpy
52
+
53
+ - run: bundle install
54
+
55
+ - run: rake compile
56
+
57
+ - run: python lib/pycall/python/investigator.py
58
+
59
+ - run: rake
60
+ env:
61
+ PYTHON: python
62
+
63
+ conda:
64
+ name: conda:ruby-${{ matrix. ruby }}/python-${{ matrix.python }}
65
+ runs-on: windows-latest
66
+
67
+ strategy:
68
+ fail-fast: false
69
+ matrix:
70
+ ruby:
71
+ - "3.0"
72
+ python:
73
+ - 3.8
74
+
75
+ defaults:
76
+ run:
77
+ shell: pwsh
78
+
79
+ steps:
80
+ - uses: actions/checkout@v2
81
+ with:
82
+ fetch-depth: 1
83
+
84
+ - uses: conda-incubator/setup-miniconda@v2
85
+ with:
86
+ activate-environment: test
87
+ python-version: ${{ matrix.python }}
88
+
89
+ - run: set
90
+ shell: cmd
91
+
92
+ - name: Add conda's DLL path
93
+ run: |
94
+ echo $env:CONDA\Library\bin >> $GITHUB_PATH
95
+ echo $env:CONDA_PREFIX\Library\bin >> $GITHUB_PATH
96
+
97
+ - uses: ruby/setup-ruby@v1
98
+ if: matrix.ruby_version != 'master-nightly'
99
+ with:
100
+ ruby-version: ${{ matrix.ruby }}
101
+
102
+ - run: conda install numpy
103
+
104
+ - run: python -c 'import numpy; print(numpy)'
105
+
106
+ - run: python -c 'import os; print(os.environ)'
107
+
108
+ - run: bundle install
109
+
110
+ - run: rake compile
111
+
112
+ - run: python lib/pycall/python/investigator.py
113
+
114
+ - run: |
115
+ ruby -Ilib -Iext/pycall -rpycall -e "p PyCall.sys.version"
116
+ ruby -Ilib -Iext/pycall -rpycall -e "PyCall.import_module(:numpy)"
117
+ env:
118
+ PYTHON: python
119
+ continue-on-error: true
120
+
121
+ - run: |
122
+ echo $env:PATH
123
+ rake
124
+ env:
125
+ PYTHON: python
126
+ CONDA_DLL_SEARCH_MODIFICATION_ENABLE: 1
127
+ continue-on-error: true
data/.gitignore CHANGED
@@ -10,6 +10,8 @@
10
10
 
11
11
  __pycache__/
12
12
  .ipynb_checkpoints/
13
+ /ext/**/Makefile
14
+ /ext/**/mkmf.log
13
15
  *.bundle
14
16
  *.so
15
17
  *.o
data/CHANGES.md CHANGED
@@ -1,6 +1,44 @@
1
1
  # The change history of PyCall
2
2
 
3
- ## master
3
+ ## 1.4.0
4
+
5
+ * Explicitly states that Windows is not supported yet in README
6
+ * Add PyCall.same?
7
+ * Improve conda support
8
+ * Fat gem is no longer supported
9
+ * Use WeakMap for caching PyPtr instances
10
+
11
+ ## 1.3.1
12
+
13
+ * Stop using `&proc` idiom to prevent warnings
14
+
15
+ *Kenta Murata*
16
+
17
+ ## 1.3.0
18
+
19
+ * Add `PyCall.without_gvl` for explicitly releasing the RubyVM GVL
20
+
21
+ * Fix for missing if in PyObjectWrapper
22
+
23
+ *Kouhei Sutou*
24
+
25
+ * Fix for Anaconda environment
26
+
27
+ *Ryo MATSUMIYA*
28
+
29
+ * Fix against `unknown symbol "PyInt_AsSsize_t"` (Fiddle::DLError)
30
+
31
+ *Kouhei Sutou*
32
+
33
+ * Fix for `TypeError: Compared with non class/module`
34
+
35
+ *Archonic*
36
+
37
+ ## 1.2.1
38
+
39
+ * Prevent circular require in pycall/iruby.rb
40
+
41
+ ## 1.2.0
4
42
 
5
43
  * Add `PyCall::Tuple#to_ary`
6
44
 
data/README.md CHANGED
@@ -5,8 +5,8 @@
5
5
 
6
6
  # PyCall: Calling Python functions from the Ruby language
7
7
 
8
- [![Build Status](https://travis-ci.org/mrkn/pycall.rb.svg?branch=master)](https://travis-ci.org/mrkn/pycall.rb)
9
- [![Build status](https://ci.appveyor.com/api/projects/status/071is0f4iu0vy8lp/branch/master?svg=true)](https://ci.appveyor.com/project/mrkn/pycall/branch/master)
8
+ [![Build Status](https://github.com/mrkn/pycall.rb/workflows/CI/badge.svg)](https://github.com/mrkn/pycall.rb/actions?query=workflow%3ACI)
9
+ [![Build status](https://ci.appveyor.com/api/projects/status/0fad23u4qj1yr49e/branch/master?svg=true)](https://ci.appveyor.com/project/mrkn/pycall-rb/branch/master)
10
10
 
11
11
  This library provides the features to directly call and partially interoperate
12
12
  with Python from the Ruby language. You can import arbitrary Python modules
@@ -15,7 +15,7 @@ Ruby to Python.
15
15
 
16
16
  ## Supported Ruby versions
17
17
 
18
- pycall.rb supports Ruby version 2.3 or higher.
18
+ pycall.rb supports Ruby version 2.4 or higher.
19
19
 
20
20
  ## Supported Python versions
21
21
 
@@ -32,6 +32,12 @@ pyenv does not build the shared library in default, so you need to specify `--en
32
32
  $ env PYTHON_CONFIGURE_OPTS='--enable-shared' pyenv install 3.7.2
33
33
  ```
34
34
 
35
+ ## Note for Windows users
36
+
37
+ Currently, pycall.rb does not support Windows. Please try to use pycall.rb on WSL2 environment.
38
+
39
+ On Windows, the error "[BUG] object allocation during garbage collection phase" is occurred at unpredictable timings.
40
+
35
41
  ## Installation
36
42
 
37
43
  Add this line to your application's Gemfile:
@@ -61,6 +67,86 @@ the `Math.sin` in Ruby:
61
67
  Type conversions from Ruby to Python are automatically performed for numeric,
62
68
  boolean, string, arrays, and hashes.
63
69
 
70
+ ### Calling a constructor
71
+
72
+ In Python, we call the constructor of a class by `classname(x, y, z)` syntax. Pycall.rb maps this syntax to `classname.new(x, y, z)`.
73
+
74
+ ### Calling a callable object
75
+
76
+ In Python, we can call the callable object by `obj(x, y, z)` syntax. PyCall.rb maps this syntax to `obj.(x, y, z)`.
77
+
78
+ ### Passing keyword arguments
79
+
80
+ In Python, we can pass keyword arguments by `func(x=1, y=2, z=3)` syntax. In pycallrb, we should rewrite `x=1` to `x: 1`.
81
+
82
+ ### The callable attribute of an object
83
+
84
+ Pycall.rb maps the callable attribute of an object to the instance method of the corresponding wrapper object. So, we can write a Python expression `obj.meth(x, y, z=1)` as `obj.meth(x, y, z: 1)` in Ruby. This mapping allows us to call these attributes naturally as Ruby's manner.
85
+
86
+ But, unfortunately, this mapping prohibits us to get the callable attributes. We need to write `PyCall.getattr(obj, :meth)` in Ruby to get `obj.meth` object while we can write `obj.meth` in Python.
87
+
88
+ ### Specifying the Python version
89
+
90
+ If you want to use a specific version of Python instead of the default,
91
+ you can change the Python version by setting the `PYTHON` environment variable
92
+ to the path of the `python` executable.
93
+
94
+ When `PYTHON` is not specified, pycall.rb tries to use `python3` first,
95
+ and then tries to use `python`.
96
+
97
+ ### Releasing the RubyVM GVL during Python function calls
98
+
99
+ You may want to release the RubyVM GVL when you call a Python function that takes very long runtime.
100
+ PyCall provides `PyCall.without_gvl` method for such purpose. When PyCall performs python function call,
101
+ PyCall checks the current context, and then it releases the RubyVM GVL when the current context is in a `PyCall.without_gvl`'s block.
102
+
103
+ ```ruby
104
+ PyCall.without_gvl do
105
+ # In this block, all Python function calls are performed without
106
+ # the GVL acquisition.
107
+ pyobj.long_running_function()
108
+ end
109
+
110
+ # Outside of PyCall.without_gvl block,
111
+ # all Python function calls are performed with the GVL acquisition.
112
+ pyobj.long_running_function()
113
+ ```
114
+
115
+ ### Debugging python finder
116
+
117
+ When you encounter `PyCall::PythonNotFound` error, you can investigate PyCall's python finder by setting `PYCALL_DEBUG_FIND_LIBPYTHON` environment variable to `1`. You can see the log like below:
118
+
119
+ ```
120
+ $ PYCALL_DEBUG_FIND_LIBPYTHON=1 ruby -rpycall -ePyCall.builtins
121
+ DEBUG(find_libpython) find_libpython(nil)
122
+ DEBUG(find_libpython) investigate_python_config("python3")
123
+ DEBUG(find_libpython) libs: ["Python.framework/Versions/3.7/Python", "Python", "libpython3.7m", "libpython3.7", "libpython"]
124
+ DEBUG(find_libpython) libpaths: ["/opt/brew/opt/python/Frameworks/Python.framework/Versions/3.7/lib", "/opt/brew/opt/python/lib", "/opt/brew/opt/python/Frameworks", "/opt/brew/Cellar/python/3.7.2_1/Frameworks/Python.framework/Versions/3.7", "/opt/brew/Cellar/python/3.7.2_1/Frameworks/Python.framework/Versions/3.7/lib"]
125
+ DEBUG(find_libpython) Unable to find /opt/brew/opt/python/Frameworks/Python.framework/Versions/3.7/lib/Python.framework/Versions/3.7/Python
126
+ DEBUG(find_libpython) Unable to find /opt/brew/opt/python/Frameworks/Python.framework/Versions/3.7/lib/Python.framework/Versions/3.7/Python.dylib
127
+ DEBUG(find_libpython) Unable to find /opt/brew/opt/python/Frameworks/Python.framework/Versions/3.7/lib/darwin/Python.framework/Versions/3.7/Python
128
+ DEBUG(find_libpython) Unable to find /opt/brew/opt/python/Frameworks/Python.framework/Versions/3.7/lib/darwin/Python.framework/Versions/3.7/Python.dylib
129
+ DEBUG(find_libpython) Unable to find /opt/brew/opt/python/lib/Python.framework/Versions/3.7/Python
130
+ DEBUG(find_libpython) Unable to find /opt/brew/opt/python/lib/Python.framework/Versions/3.7/Python.dylib
131
+ DEBUG(find_libpython) Unable to find /opt/brew/opt/python/lib/darwin/Python.framework/Versions/3.7/Python
132
+ DEBUG(find_libpython) Unable to find /opt/brew/opt/python/lib/darwin/Python.framework/Versions/3.7/Python.dylib
133
+ DEBUG(find_libpython) dlopen("/opt/brew/opt/python/Frameworks/Python.framework/Versions/3.7/Python") = #<Fiddle::Handle:0x00007fc012048650>
134
+ ```
135
+
136
+ ## Special notes for specific libraries
137
+
138
+ ### matplotlib
139
+
140
+ Use [mrkn/matplotlib.rb](https://github.com/mrkn/matplotlib.rb) instead of just importing it by `PyCall.import_module("matplotlib")`.
141
+
142
+ ### numpy
143
+
144
+ Use [mrkn/numpy.rb](https://github.com/mrkn/numpy.rb) instead of just importing it by `PyCall.import_module("numpy")`.
145
+
146
+ ### pandas
147
+
148
+ Use [mrkn/pandas.rb](https://github.com/mrkn/pandas.rb) instead of just importing it by `PyCall.import_module("pandas")`.
149
+
64
150
  ## PyCall object system
65
151
 
66
152
  PyCall wraps pointers of Python objects in `PyCall::PyPtr` objects.
@@ -80,11 +166,71 @@ variable `@__pyptr__`. `PyCall::PyObjectWrapper` assumes the existance of
80
166
  system and Python object system. For example, `PyCall::PyObjectWrapper`
81
167
  translates Ruby's coerce system into Python's swapped operation protocol.
82
168
 
83
- ### Specifying the Python version
169
+ ## Deploying on Heroku
84
170
 
85
- If you want to use a specific version of Python instead of the default,
86
- you can change the Python version by setting the `PYTHON` environment variable
87
- to the path of the `python` executable.
171
+ Heroku's default version of Python is not compiled with the `--enabled-shared`
172
+ option and can't be accessed by PyCall. Alternative [buildpacks](https://devcenter.heroku.com/articles/buildpacks) are available,
173
+ including these that have been reported to work with PyCall:
174
+
175
+ https://github.com/richgong/heroku-buildpack-python
176
+ https://github.com/dsounded/heroku-buildpack-python
177
+ https://github.com/ReforgeHQ/heroku-buildpack-python
178
+
179
+ These community-developed buildpacks are not supported by Heroku, so it's
180
+ worth examining the source to make sure the buildpack you use suits your
181
+ needs. For instance, 'ReforgeHQ' works well with Python 3.8.1, but has not
182
+ been configured to work with other versions and may not be as generally
183
+ useful as the 'dsounded' or 'richgong' buildpacks.
184
+
185
+ The buildpack will expect to find both a `runtime.txt` and a `requirements.txt`
186
+ file in the root of your project. You will need to add these to specify the
187
+ version of Python and any packages to be installed via `pip`, _e.g_ to use
188
+ version Python 3.8.1 and version 2.5 of the 'networkx' package:
189
+
190
+ $ echo "python-3.8.1" >> runtime.txt
191
+ $ echo "networkx==2.5" >> requirements.txt
192
+
193
+ Commit these two files into project's repository. You'll use these to manage
194
+ your Python environment in much the same way you use the `Gemfile` to manage
195
+ Ruby.
196
+
197
+ Heroku normally detects which buildpacks to use, but you will want to override
198
+ this behavior. It's probably best to clear out existing buildpacks and specify
199
+ exactly which buildpacks from scratch.
200
+
201
+ First, take stock of your existing buildpacks:
202
+
203
+ $ heroku buildpack [-a YOUR_APP_NAME]
204
+
205
+ For a Ruby/Rails application this will typically report the stock `heroku/ruby`
206
+ buildpack, or possibly both `heroku/ruby` and `heroku/nodejs`.
207
+
208
+ Clear the list and progressively add back your buildpacks, starting with the Python
209
+ community-developed buildpack. For example, if `ruby` and `nodejs` buildpacks were
210
+ previously installed, and chosing the 'ReforgeHQ' buildback, your setup process will
211
+ be similar to this:
212
+
213
+ $ heroku buildpacks:clear
214
+ $ heroku buildpacks:add https://github.com/ReforgeHQ/heroku-buildpack-python -i 1
215
+ $ heroku buildpacks:add heroku/nodejs -i 2
216
+ # heroku buildpacks:add heroku/ruby -i 3
217
+
218
+ If you have multiple applications on Heroku you will need to append each of these
219
+ with application's identifier (_e.g._ `heroku buildpacks:clear -a YOUR_APP_NAME`).
220
+
221
+ With each buildpack we are registering its index (the `-i` switch) in order to
222
+ specify the order Heroku will load runtimes and execute bootstrapping code. It's
223
+ important for the Python environment to be engaged first, as PyCall will need to
224
+ be able to find it when Ruby-based processes start.
225
+
226
+ Once you have set up your buildpacks, and have commited both `requirements.txt` and
227
+ `runtime.txt` files to git, deploy your Heroku application as your normally would.
228
+ The Python bootstrapping process will appear in the log first, followed by the Ruby
229
+ and so on. PyCall should now be able to successfully call Python functions from
230
+ within the Heroku environment.
231
+
232
+ NB It is also possible to specify buildpacks within Docker images on Heroku.
233
+ See Heroku's [documentation on using Docker Images](https://devcenter.heroku.com/articles/build-docker-images-heroku-yml).
88
234
 
89
235
  ## Development
90
236