Skip to content

Commit ee55517

Browse files
committed
Merge branch 'main' into pysr-integration-test
2 parents 977296d + ce54b86 commit ee55517

Some content is hidden

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

97 files changed

+4076
-2161
lines changed

.JuliaFormatter.toml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
ignore = [
2+
"examples",
3+
".git",
4+
".CondaPkg",
5+
".ipynb_checkpoints",
6+
".pytest_cache",
7+
".venv",
8+
]

.github/workflows/docscleanup.yml

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -15,16 +15,15 @@ jobs:
1515

1616
- name: Delete preview and history
1717
run: |
18-
git config user.name "Documenter.jl"
19-
git config user.email "[email protected]"
20-
git rm -rf "previews/PR$PRNUM"
21-
git commit -m "delete preview"
22-
git branch gh-pages-new $(echo "delete history" | git commit-tree HEAD^{tree})
18+
if [ -d "$DIR" ]; then
19+
git config user.name "Documenter.jl"
20+
git config user.email "[email protected]"
21+
git rm -rf "$DIR"
22+
git commit -m "delete preview"
23+
git branch gh-pages-new $(echo "delete history" | git commit-tree HEAD^{tree})
24+
git push --force origin gh-pages-new:gh-pages
25+
fi
2326
env:
24-
PRNUM: ${{ github.event.number }}
27+
DIR: "previews/PR${{ github.event.number }}"
2528

26-
- name: Push changes
27-
run: |
28-
git push --force origin gh-pages-new:gh-pages
29-
3029
# Workflow copied from https://github.com/CliMA/TimeMachine.jl

.github/workflows/tagbot.yml

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,22 @@ on:
44
types:
55
- created
66
workflow_dispatch:
7+
inputs:
8+
lookback:
9+
default: "3"
10+
permissions:
11+
actions: read
12+
checks: read
13+
contents: write
14+
deployments: read
15+
issues: read
16+
discussions: read
17+
packages: read
18+
pages: read
19+
pull-requests: read
20+
repository-projects: read
21+
security-events: read
22+
statuses: read
723
jobs:
824
TagBot:
925
if: github.event_name == 'workflow_dispatch' || github.actor == 'JuliaTagBot'
@@ -12,4 +28,6 @@ jobs:
1228
- uses: JuliaRegistries/TagBot@v1
1329
with:
1430
token: ${{ secrets.GITHUB_TOKEN }}
31+
# Edit the following line to reflect the actual name of the GitHub Secret containing your private key
1532
ssh: ${{ secrets.DOCUMENTER_KEY }}
33+
# ssh: ${{ secrets.NAME_OF_MY_SSH_PRIVATE_KEY_SECRET }}

.github/workflows/tests-nightly.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ jobs:
3838
- uses: julia-actions/julia-runtest@v1
3939
env:
4040
JULIA_DEBUG: PythonCall
41+
JULIA_NUM_THREADS: '2'
4142
- uses: julia-actions/julia-processcoverage@v1
4243
- uses: codecov/codecov-action@v1
4344
with:

.github/workflows/tests.yml

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ jobs:
4343
uses: julia-actions/julia-runtest@v1
4444
env:
4545
JULIA_DEBUG: PythonCall
46+
JULIA_NUM_THREADS: '2'
4647
- name: Process coverage
4748
uses: julia-actions/julia-processcoverage@v1
4849
- name: Upload coverage to Codecov
@@ -56,17 +57,21 @@ jobs:
5657
fail-fast: true
5758
matrix:
5859
os: [ubuntu-latest, windows-latest, macos-latest]
59-
pyversion: ["3.x", "3.7"]
60+
pyversion: ["3.x", "3.8"]
6061
steps:
6162
- uses: actions/checkout@v3
6263
- name: Set up Python ${{ matrix.pyversion }}
6364
uses: actions/setup-python@v4
6465
with:
6566
python-version: ${{ matrix.pyversion }}
67+
- name: Set up Julia
68+
uses: julia-actions/setup-julia@v1
69+
with:
70+
version: '1'
6671
- name: Install dependencies
6772
run: |
6873
python -m pip install --upgrade pip
69-
pip install flake8 pytest pytest-cov virtualenv
74+
pip install flake8 pytest pytest-cov nbval numpy virtualenv
7075
cp pysrc/juliacall/juliapkg-dev.json pysrc/juliacall/juliapkg.json
7176
pip install -e .
7277
- name: Lint with flake8
@@ -77,7 +82,9 @@ jobs:
7782
flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics
7883
- name: Run tests
7984
run: |
80-
pytest -s --cov=pysrc
85+
pytest -s --nbval --cov=pysrc ./pytest/
86+
env:
87+
PYTHON_JULIACALL_THREADS: '2'
8188
- name: Upload coverage to Codecov
8289
uses: codecov/codecov-action@v2
8390
env:

CondaPkg.toml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
[deps.libstdcxx-ng]
22
version = "<=julia"
33

4+
[deps.openssl]
5+
version = "<=julia"
6+
47
[deps.python]
58
build = "**cpython**"
6-
version = ">=3.7,<4"
9+
version = ">=3.8,<4"

Project.toml

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name = "PythonCall"
22
uuid = "6099a3de-0909-46bc-b1f4-468b9a2dfc0d"
33
authors = ["Christopher Doris <github.com/cjdoris>"]
4-
version = "0.9.15"
4+
version = "0.9.23"
55

66
[deps]
77
CondaPkg = "992eb4ea-22a4-4c89-a5bb-47a3300528ab"
@@ -17,10 +17,19 @@ Tables = "bd369af6-aec1-5ad0-b16a-f7cc5008161c"
1717
UnsafePointers = "e17b2a0c-0bdf-430a-bd0c-3a23cae4ff39"
1818

1919
[compat]
20-
CondaPkg = "0.2.21"
20+
Aqua = "0 - 999"
21+
CondaPkg = "0.2.23"
22+
Dates = "1"
23+
Libdl = "1"
2124
MacroTools = "0.5"
25+
Markdown = "1"
26+
Pkg = "1"
27+
REPL = "1"
2228
Requires = "1"
29+
Serialization = "1"
2330
Tables = "1"
31+
Test = "1"
32+
TestItemRunner = "0 - 999"
2433
UnsafePointers = "1"
2534
julia = "1.6.1"
2635

README.md

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<h1><img src="https://raw.githubusercontent.com/JuliaPy/PythonCall.jl/main/docs/src/assets/logo.png" alt="PythonCall.jl logo" style="width: 100px;"><br>PythonCall &amp;&nbsp;JuliaCall</h1>
1+
<h1><img src="docs/src/assets/logo.png" alt="PythonCall.jl logo" style="width: 100px;"><br>PythonCall &amp;&nbsp;JuliaCall</h1>
22

33
[![Project Status: Active – The project has reached a stable, usable state and is being actively developed.](https://www.repostatus.org/badges/latest/active.svg)](https://www.repostatus.org/#active)
44
[![Stable Documentation](https://img.shields.io/badge/docs-stable-blue.svg)](https://juliapy.github.io/PythonCall.jl/stable)
@@ -14,7 +14,7 @@ Bringing [**Python®**](https://www.python.org/) and [**Julia**](https://juliala
1414
- Fast non-copying conversion of numeric arrays in either direction: modify Python arrays (e.g. `bytes`, `array.array`, `numpy.ndarray`) from Julia or Julia arrays from Python.
1515
- Helpful wrappers: interpret Python sequences, dictionaries, arrays, dataframes and IO streams as their Julia counterparts, and vice versa.
1616
- Beautiful stack-traces.
17-
- Supports modern systems: tested on Windows, MacOS and Linux, 64-bit, Julia 1.6.1 upwards and Python 3.7 upwards.
17+
- Supports modern systems: tested on Windows, MacOS and Linux, 64-bit, Julia 1.6.1 upwards and Python 3.8 upwards.
1818

1919
⭐ If you like this, a GitHub star would be lovely thank you. ⭐
2020

@@ -40,9 +40,8 @@ In this example we use the Python module JuliaCall from an IPython notebook to t
4040

4141
## What about PyCall?
4242

43-
The existing package [PyCall](https://github.com/JuliaPy/PyCall.jl) is another similar interface to Python. Here we note some key differences, but a more detailed comparison is in the documentation.
43+
The existing package [PyCall](https://github.com/JuliaPy/PyCall.jl) is another similar interface to Python. Here we note some key differences:.
4444
- PythonCall supports a wider range of conversions between Julia and Python, and the conversion mechanism is extensible.
4545
- PythonCall by default never copies mutable objects when converting, but instead directly wraps the mutable object. This means that modifying the converted object modifies the original, and conversion is faster.
4646
- PythonCall does not usually automatically convert results to Julia values, but leaves them as Python objects. This makes it easier to do Pythonic things with these objects (e.g. accessing methods) and is type-stable.
47-
- PythonCall installs dependencies into a separate Conda environment for each Julia project. This means each Julia project can have an isolated set of Python dependencies.
48-
- PythonCall supports Julia 1.6.1+ and Python 3.7+ whereas PyCall supports Julia 0.7+ and Python 2.7+.
47+
- PythonCall installs dependencies into a separate Conda environment for each Julia project using [CondaPkg](https://github.com/JuliaPy/CondaPkg.jl). This means each Julia project can have an isolated set of Python dependencies.

bump.jl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ function bump(file, oldpat, newpat)
99
oldtext = read(file, String)
1010
newtext = replace(oldtext, oldpat => newpat)
1111
@assert newtext != oldtext
12-
write(file, newtext)
12+
write(file, newtext)
1313
end
1414

1515
function bumpver(file, pattern, oldver, newver)
@@ -27,4 +27,5 @@ bumpver("pysrc/juliacall/__init__.py", "__version__ = '{}'\n", oldver, newver)
2727
bumpver("pysrc/juliacall/juliapkg.json", "\"version\": \"={}\"", oldver, newver)
2828
bumpver("pysrc/juliacall/juliapkg-dev.json", "\"version\": \"={}\"", oldver, newver)
2929
bumpver("src/PythonCall.jl", "VERSION = v\"{}\"", oldver, newver)
30+
bumpver("src/Core/Core.jl", "VERSION = v\"{}\"", oldver, newver)
3031
bump("docs/src/releasenotes.md", "## Unreleased", "## $newver ($(today()))")

docs/customdocs.jl

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,8 @@ function runner(::Type{CustomDocExpander}, node, page, doc)
5353
Dict{Symbol,Any}( # NOTE: Not sure about what to put here.
5454
:module => Main, # This is supposed to be tracking python code.
5555
:path => "",
56-
:linenumber => 0
57-
)
56+
:linenumber => 0,
57+
),
5858
)::Docs.DocStr
5959

6060
# NOTE: This was modified because the original Documenter.create_docsnode was generating unreachable links
@@ -80,12 +80,10 @@ function _parse_docs(code::AbstractString)
8080
m = match(r"^(.+?)\s*-\s*(.+?)\s*(\n[\s\S]*)$", strip(code))
8181

8282
if isnothing(m)
83-
error(
84-
"""
85-
Invalid docstring:
86-
$(code)
87-
"""
88-
)
83+
error("""
84+
Invalid docstring:
85+
$(code)
86+
""")
8987
end
9088

9189
name = Symbol(m[1])
@@ -134,4 +132,4 @@ function _create_docsnode(docstring, result, object, page, doc)
134132
return MarkdownAST.Node(docsnode)
135133
end
136134

137-
end # module CustomDocs
135+
end # module CustomDocs

docs/make.jl

Lines changed: 7 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,29 +5,22 @@ include("customdocs.jl")
55
makedocs(
66
sitename = "PythonCall & JuliaCall",
77
modules = [PythonCall],
8+
format = Documenter.HTML(assets = ["assets/favicon.ico"]),
89
warnonly = [:missing_docs], # avoid raising error when docs are missing
910
pages = [
1011
"Home" => "index.md",
11-
"The Julia module PythonCall" => [
12-
"Guide" => "pythoncall.md",
13-
"Reference" => "pythoncall-reference.md",
14-
],
15-
"The Python module JuliaCall" => [
16-
"Guide" => "juliacall.md",
17-
"Reference" => "juliacall-reference.md",
18-
],
12+
"The Julia module PythonCall" =>
13+
["Guide" => "pythoncall.md", "Reference" => "pythoncall-reference.md"],
14+
"The Python module JuliaCall" =>
15+
["Guide" => "juliacall.md", "Reference" => "juliacall-reference.md"],
1916
"Conversion" => [
2017
"Julia to Python" => "conversion-to-python.md",
2118
"Python to Julia" => "conversion-to-julia.md",
2219
],
2320
"compat.md",
2421
"faq.md",
25-
"pycall.md",
2622
"releasenotes.md",
27-
]
23+
],
2824
)
2925

30-
deploydocs(
31-
repo = raw"github.com/JuliaPy/PythonCall.jl.git",
32-
push_preview = true
33-
)
26+
deploydocs(repo = raw"github.com/JuliaPy/PythonCall.jl.git", push_preview = true)

docs/src/assets/favicon.ico

49.4 KB
Binary file not shown.

docs/src/assets/logo.png

31.8 KB
Loading

docs/src/compat.md

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,12 @@ functions to bridge a gap. We aim to keep these as minimal as possible.
99

1010
Whenever a Python exception is displayed by Julia, `sys.last_traceback` and friends are set. This allows the post-mortem debugger `pdb.pm()` to work. Disable by setting `PythonCall.CONFIG.auto_sys_last_traceback = false`.
1111

12+
## Julia standard library
13+
14+
Python objects can be serialised with the [`Serialization`](https://docs.julialang.org/en/v1/stdlib/Serialization/) stdlib.
15+
This uses [`pickle`](https://docs.python.org/3/library/pickle.html) library under the hood.
16+
You can opt into using [`dill`](https://pypi.org/project/dill/) instead by setting the environment variable `JULIA_PYTHONCALL_PICKLE="dill"`.
17+
1218
## Tabular data / Pandas
1319

1420
The abstract type [`PyTable`](@ref) is for wrapper types around Python tables, providing the
@@ -67,8 +73,9 @@ The `juliacall` IPython extension adds these features to your IPython session:
6773

6874
The extension is experimental and unstable - the API can change at any time.
6975

70-
Enable the extension with `%load_ext juliacall`.
71-
See [the IPython docs](https://ipython.readthedocs.io/en/stable/config/extensions/).
76+
You can explicitly enable the extension with `%load_ext juliacall`, but
77+
it will automatically be loaded if `juliacall` is imported and IPython is detected.
78+
You can disable this behavior with an [environment variable](@ref julia-config).
7279

7380
The `%%julia` cell magic can synchronise variables between Julia and Python by listing them
7481
on the first line:
@@ -88,6 +95,9 @@ In [5]: z
8895
Out[5]: '2^8 = 256'
8996
```
9097

98+
Also see [the IPython docs](https://ipython.readthedocs.io/en/stable/config/extensions/)
99+
for more information on extensions.
100+
91101
## Asynchronous Julia code (including Makie)
92102

93103
Asynchronous Julia code will not normally run while Python is executing, unless it is in a

docs/src/conversion-to-julia.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ From Python, the arguments to a Julia function will be converted according to th
4747
| `ctypes.c_voidp` | `Ptr{Cvoid}`, `Ptr` |
4848
| `ctypes.c_char_p` | `Cstring`, `Ptr{Cchar}`, `Ptr` |
4949
| `ctypes.c_wchar_p` | `Cwstring`, `Ptr{Cwchar}`, `Ptr` |
50-
| `numpy.intXX`/`numpy.uintXX`/`numpy.floatXX` | `Integer`, `Rational`, `Real`, `Number` |
50+
| `numpy.bool_`/`numpy.intXX`/`numpy.uintXX`/`numpy.floatXX` | `Bool`, `Integer`, `Rational`, `Real`, `Number` |
5151
| Objects satisfying the buffer or array interface | `Array`, `AbstractArray` |
5252
| **Low priority (fallback to `Py`).** | |
5353
| Anything | `Py` |

docs/src/faq.md

Lines changed: 18 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,27 @@
11
# FAQ & Troubleshooting
22

3-
## Is PythonCall/JuliaCall thread safe?
3+
## Can I use PythonCall and PyCall together?
44

5-
No.
5+
Yes, you can use both PyCall and PythonCall in the same Julia session. This is platform-dependent:
6+
- On most systems the Python interpreter used by PythonCall and PyCall must be the same (see below).
7+
- On Windows it appears to be possible for PythonCall and PyCall to use different interpreters.
68

7-
Some rules if you are writing multithreaded code:
8-
- Only call Python functions from the first thread.
9-
- You probably also need to call `PythonCall.GC.disable()` on the main thread before any
10-
threaded block of code. Remember to call `PythonCall.GC.enable()` again afterwards.
11-
(This is because Julia finalizers can be called from any thread.)
12-
- Julia intentionally causes segmentation faults as part of the GC safepoint mechanism.
13-
If unhandled, these segfaults will result in termination of the process. To enable signal handling,
14-
set `PYTHON_JULIACALL_HANDLE_SIGNALS=yes` before any calls to import juliacall. This is equivalent
15-
to starting julia with `julia --handle-signals=yes`, the default behavior in Julia.
16-
See discussion [here](https://github.com/JuliaPy/PythonCall.jl/issues/219#issuecomment-1605087024) for more information.
17-
- You may still encounter problems.
9+
To force PythonCall to use the same Python interpreter as PyCall, set the environment variable [`JULIA_PYTHONCALL_EXE`](@ref pythoncall-config) to `"@PyCall"`. Note that this will opt out of automatic dependency management using CondaPkg.
1810

19-
Related issues: [#201](https://github.com/JuliaPy/PythonCall.jl/issues/201), [#202](https://github.com/JuliaPy/PythonCall.jl/issues/202)
11+
Alternatively, to force PyCall to use the same interpreter as PythonCall, set the environment variable `PYTHON` to [`PythonCall.python_executable_path()`](@ref) and then `Pkg.build("PyCall")`. You will need to do this each time you change project, because PythonCall by default uses a different Python for each project.
2012

21-
## Does it work on Apple silicon (ARM, M1, M2, ...)?
13+
## Is PythonCall/JuliaCall thread safe?
2214

23-
Maybe. Your mileage may vary.
15+
Yes, as of v0.9.22, provided you handle the GIL correctly. See the guides for
16+
[PythonCall](@ref jl-multi-threading) and [JuliaCall](@ref py-multi-threading).
2417

25-
In general, PythonCall and JuliaCall are only supported on platforms with
26-
[Tier 1](https://julialang.org/downloads/#supported_platforms) level of support by Julia.
27-
Currently, Apple silicon is Tier 2, so is not supported.
18+
Before, tricks such as disabling the garbage collector were required. See the
19+
[old docs](https://juliapy.github.io/PythonCall.jl/v0.9.21/faq/#Is-PythonCall/JuliaCall-thread-safe?).
2820

29-
Due to time constraints, issues affecting only unsupported platforms will not be
30-
investigated. It is much more likely to be an issue with Julia itself than PythonCall.
21+
Related issues:
22+
[#201](https://github.com/JuliaPy/PythonCall.jl/issues/201),
23+
[#202](https://github.com/JuliaPy/PythonCall.jl/issues/202),
24+
[#529](https://github.com/JuliaPy/PythonCall.jl/pull/529)
3125

3226
## Issues when Numpy arrays are expected
3327

@@ -92,4 +86,6 @@ Related issues: [#255](https://github.com/JuliaPy/PythonCall.jl/issues/255)
9286

9387
## Can I use JuliaCall to run Julia inside applications with embedded Python?
9488

95-
Yes, it may be possible. See an example of how to have Julia running inside the Python that is running inside Blender here https://discourse.julialang.org/t/running-julia-inside-blender-through-vscode-using-pythoncall-juliacall/96838.
89+
Yes, it may be possible. A good example of that is having Julia running inside the Python that is running inside Blender, as presented in [this Discourse post](https://discourse.julialang.org/t/running-julia-inside-blender-through-vscode-using-pythoncall-juliacall/96838/6).
90+
From the point that one has JuliaCall running inside Python, if it has access to the terminal, one can even launch a Julia REPL there, and if needed connect with VSCode Julia extension to it.
91+
The full Python script to install, launch JuliaCall, and launch a Julia REPL in Blender is [here](https://gist.github.com/cdsousa/d820d27174238c0d48e5252355584172).

docs/src/index.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,4 @@ Bringing [**Python®**](https://www.python.org/) and [**Julia**](https://juliala
77
- Fast non-copying conversion of numeric arrays in either direction: modify Python arrays (e.g. `bytes`, `array.array`, `numpy.ndarray`) from Julia or Julia arrays from Python.
88
- Helpful wrappers: interpret Python sequences, dictionaries, arrays, dataframes and IO streams as their Julia counterparts, and vice versa.
99
- Beautiful stack-traces.
10-
- Works anywhere: tested on Windows, MacOS and Linux, 32- and 64-bit, Julia Julia 1.6.1 upwards and Python 3.7 upwards.
10+
- Works anywhere: tested on Windows, MacOS and Linux, 32- and 64-bit, Julia Julia 1.6.1 upwards and Python 3.8 upwards.

0 commit comments

Comments
 (0)