# Matplotlib rcParams in module \_\_init\_\_() function segfault on M1

**URL:** <https://discourse.julialang.org/t/matplotlib-rcparams-in-module-init-function-segfault-on-m1/103314>\
**Category:** General Usage\
**Tags:** pythoncall, pythonplot\
**Created:** [August 28, 2023, 10:28pm UTC](https://discourse.julialang.org/t/matplotlib-rcparams-in-module-init-function-segfault-on-m1/103314 "2023-08-28T22:28:18Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![hsgg](https://avatars.discourse-cdn.com/v4/letter/h/838e76/32.png) [@hsgg](https://discourse.julialang.org/u/hsgg)\
**Post date:** [August 28, 2023, 10:28pm UTC](https://discourse.julialang.org/t/matplotlib-rcparams-in-module-init-function-segfault-on-m1/103314/1 "2023-08-28T22:28:19Z")

</div>

Hi, I am converting a package from PyCall.jl to PythonCall.jl. (I am planning on calling Julia from Python in the future, and I want to test whether to use PythonCall/JuliaCall or PyCall/pyjulia. PythonCall/JuliaCall appears to be the future, so I’m pursuing that route now. However, I had a similar problem with PyCall - I just never bothered to investigate.)

So I have two packages: MyPlotExtras.jl and another that loads MyPlotExtras. A minimal example is:

```julia
module MyPlotExtras

using PythonPlot

function __init__ ()
    rcParams = PythonPlot.matplotlib.rcParams
end

end

```

and

```julia
module TestMyPlotExtras

using MyPlotExtras

end

```

To reproduce the problem it is important to `dev` the `MyPlotExtras.jl` package in the `TestMyPlotExtras.jl` package, or to have it registered in a local registry.

I am probably failing at explaining this properly, so I made a very small git repo to illustrate: [GitHub - hsgg/TestMyPlotExtras: Testing repository to show how loading the PlotExtras package fails with PythonCall.jl](https://github.com/hsgg/TestMyPlotExtras)

Only then do I get:

```julia
julia> using TestMyPlotExtras
[11742] signal (11.2): Segmentation fault: 11
in expression starting at /Users/henry/TestMyPlotExtras/TestMyPlotExtras/src/TestMyPlotExtras.jl:3
PyObject_GetAttr at /Users/henry/TestMyPlotExtras/TestMyPlotExtras/.CondaPkg/env/lib/libpython3.11.dylib (unknown line)
PyObject_GetAttr at /Users/henry/.julia/packages/PythonCall/qTEA1/src/cpython/pointers.jl:299 [inlined]
macro expansion at /Users/henry/.julia/packages/PythonCall/qTEA1/src/Py.jl:131 [inlined]
pygetattr at /Users/henry/.julia/packages/PythonCall/qTEA1/src/abstract/object.jl:60
getproperty at /Users/henry/.julia/packages/PythonCall/qTEA1/src/Py.jl:261 [inlined]
__init__ at /Users/henry/TestMyPlotExtras/MyPlotExtras/src/MyPlotExtras.jl:6
jl_sysimg_fvars_base at /Users/henry/.julia/compiled/v1.9/MyPlotExtras/dkBtT_GM8Uw.dylib (unknown line)
ijl_apply_generic at /Applications/Julia-1.9.app/Contents/Resources/julia/lib/julia/libjulia-internal.1.9.dylib (unknown line)
jl_module_run_initializer at /Applications/Julia-1.9.app/Contents/Resources/julia/lib/julia/libjulia-internal.1.9.dylib (unknown line)
ijl_init_restored_modules at /Applications/Julia-1.9.app/Contents/Resources/julia/lib/julia/libjulia-internal.1.9.dylib (unknown line)
register_restored_modules at ./loading.jl:1115
_include_from_serialized at ./loading.jl:1061
_require_search_from_serialized at ./loading.jl:1506
_require at ./loading.jl:1783
_require_prelocked at ./loading.jl:1660
macro expansion at ./loading.jl:1648 [inlined]
macro expansion at ./lock.jl:267 [inlined]
require at ./loading.jl:1611
jfptr_require_55044 at /Applications/Julia-1.9.app/Contents/Resources/julia/lib/julia/sys.dylib (unknown line)
ijl_apply_generic at /Applications/Julia-1.9.app/Contents/Resources/julia/lib/julia/libjulia-internal.1.9.dylib (unknown line)
eval_import_path at /Applications/Julia-1.9.app/Contents/Resources/julia/lib/julia/libjulia-internal.1.9.dylib (unknown line)
jl_toplevel_eval_flex at /Applications/Julia-1.9.app/Contents/Resources/julia/lib/julia/libjulia-internal.1.9.dylib (unknown line)
jl_toplevel_eval_flex at /Applications/Julia-1.9.app/Contents/Resources/julia/lib/julia/libjulia-internal.1.9.dylib (unknown line)
jl_toplevel_eval_flex at /Applications/Julia-1.9.app/Contents/Resources/julia/lib/julia/libjulia-internal.1.9.dylib (unknown line)
ijl_toplevel_eval_in at /Applications/Julia-1.9.app/Contents/Resources/julia/lib/julia/libjulia-internal.1.9.dylib (unknown line)
eval at ./boot.jl:370 [inlined]
include_string at ./loading.jl:1903
ijl_apply_generic at /Applications/Julia-1.9.app/Contents/Resources/julia/lib/julia/libjulia-internal.1.9.dylib (unknown line)
_include at ./loading.jl:1963
include at ./Base.jl:457 [inlined]
include_package_for_output at ./loading.jl:2049
jfptr_include_package_for_output_43027 at /Applications/Julia-1.9.app/Contents/Resources/julia/lib/julia/sys.dylib (unknown line)
ijl_apply_generic at /Applications/Julia-1.9.app/Contents/Resources/julia/lib/julia/libjulia-internal.1.9.dylib (unknown line)
do_call at /Applications/Julia-1.9.app/Contents/Resources/julia/lib/julia/libjulia-internal.1.9.dylib (unknown line)
eval_body at /Applications/Julia-1.9.app/Contents/Resources/julia/lib/julia/libjulia-internal.1.9.dylib (unknown line)
jl_interpret_toplevel_thunk at /Applications/Julia-1.9.app/Contents/Resources/julia/lib/julia/libjulia-internal.1.9.dylib (unknown line)
jl_toplevel_eval_flex at /Applications/Julia-1.9.app/Contents/Resources/julia/lib/julia/libjulia-internal.1.9.dylib (unknown line)
jl_toplevel_eval_flex at /Applications/Julia-1.9.app/Contents/Resources/julia/lib/julia/libjulia-internal.1.9.dylib (unknown line)
ijl_toplevel_eval_in at /Applications/Julia-1.9.app/Contents/Resources/julia/lib/julia/libjulia-internal.1.9.dylib (unknown line)
eval at ./boot.jl:370 [inlined]
include_string at ./loading.jl:1903
include_string at ./loading.jl:1913 [inlined]
exec_options at ./client.jl:305
_start at ./client.jl:522
jfptr__start_51456 at /Applications/Julia-1.9.app/Contents/Resources/julia/lib/julia/sys.dylib (unknown line)
ijl_apply_generic at /Applications/Julia-1.9.app/Contents/Resources/julia/lib/julia/libjulia-internal.1.9.dylib (unknown line)
true_main at /Applications/Julia-1.9.app/Contents/Resources/julia/lib/julia/libjulia-internal.1.9.dylib (unknown line)
jl_repl_entrypoint at /Applications/Julia-1.9.app/Contents/Resources/julia/lib/julia/libjulia-internal.1.9.dylib (unknown line)
Allocations: 4925588 (Pool: 4922287; Big: 3301); GC: 7
ERROR: Failed to precompile TestMyPlotExtras [679a42ec-c8f9-48a5-807c-1ce16acee5ed] to "/Users/henry/.julia/compiled/v1.9/TestMyPlotExtras/jl_IJiDWn".
Stacktrace:
 [1] error(s::String)
   @ Base ./error.jl:35
 [2] compilecache(pkg::Base.PkgId, path::String, internal_stderr::IO, internal_stdout::IO, keep_loaded_modules::Bool)
   @ Base ./loading.jl:2300
 [3] compilecache
   @ ./loading.jl:2167 [inlined]
 [4] _require(pkg::Base.PkgId, env::String)
   @ Base ./loading.jl:1805
 [5] _require_prelocked(uuidkey::Base.PkgId, env::String)
   @ Base ./loading.jl:1660
 [6] macro expansion
   @ ./loading.jl:1648 [inlined]
 [7] macro expansion
   @ ./lock.jl:267 [inlined]
 [8] require(into::Module, mod::Symbol)
   @ Base ./loading.jl:1611

```

I’m on Apple M1:

```julia
julia> versioninfo()
Julia Version 1.9.3
Commit bed2cd540a1 (2023-08-24 14:43 UTC)
Build Info:
  Official https://julialang.org/ release
Platform Info:
  OS: macOS (arm64-apple-darwin22.4.0)
  CPU: 10 × Apple M1 Max
  WORD_SIZE: 64
  LIBM: libopenlibm
  LLVM: libLLVM-14.0.6 (ORCJIT, apple-m1)
  Threads: 1 on 8 virtual cores

```

---

<div class="post-metadata">

**Author:** ![hsgg](https://avatars.discourse-cdn.com/v4/letter/h/838e76/32.png) [@hsgg](https://discourse.julialang.org/u/hsgg)\
**Post date:** [August 28, 2023, 11:37pm UTC](https://discourse.julialang.org/t/matplotlib-rcparams-in-module-init-function-segfault-on-m1/103314/2 "2023-08-28T23:37:51Z")

</div>

Digging further, there is a [workaround](https://github.com/cjdoris/PythonCall.jl/pull/328) that [PythonPlot.jl](https://github.com/JuliaPy/PythonPlot.jl/blob/fe588f4e3b084b9d0ada8641939c6331def77036/src/init.jl#L147C27-L147C27) uses. Adding that to skip precompilation of ` __ini__ ()` in MyPlotExtras does seem to work. However, the PythonCall.jl author seems to say that is not a good solution.

What is a good solution?

---

<div class="post-metadata">

**Author:** ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)\
**Post date:** [August 29, 2023, 2:17am UTC](https://discourse.julialang.org/t/matplotlib-rcparams-in-module-init-function-segfault-on-m1/103314/3 "2023-08-29T02:17:31Z")

</div>

If you don’t want to use the ugly `ccall(:jl_generating_output, ...)` to check whether Julia is precompiling, you can just check whether `PythonPlot.matplotlib` is initialized:

```julia
PythonCall.pyisnull(PythonPlot.matplotlib) && return

```

---

<div class="post-metadata">

**Author:** ![cjdoris](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cjdoris/32/213133_2.png) [@cjdoris](https://discourse.julialang.org/u/cjdoris)\
**Post date:** [September 20, 2023, 7:42am UTC](https://discourse.julialang.org/t/matplotlib-rcparams-in-module-init-function-segfault-on-m1/103314/4 "2023-09-20T07:42:17Z")

</div>

The reason you get this crash is _because_ PythonPlot skips ` __init__ ` when precompiling. This means that the `matplotlib` object is not properly initialised when you access it in your own ` __init__ ` function, hence the crash.

AFAIU skipping ` __init__ ` is an antipattern, precisely for this sort of reason: as soon as one package skips ` __init__ ` then all downstream packages need to as well, because downstream ` __init__ ` functions are allowed to assume all upstream packages are properly initialised. This is why I refused to do it in PythonCall.

@stevengj why does PythonPlot do this?

---

<div class="post-metadata">

**Author:** ![cjdoris](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cjdoris/32/213133_2.png) [@cjdoris](https://discourse.julialang.org/u/cjdoris)\
**Post date:** [September 20, 2023, 7:44am UTC](https://discourse.julialang.org/t/matplotlib-rcparams-in-module-init-function-segfault-on-m1/103314/5 "2023-09-20T07:44:13Z")

</div>

Also a direct solution to your problem is to call `pyimport("matplotlib")` instead of `PythonPlot.matplotlib`.

---

<div class="post-metadata">

**Author:** ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)\
**Post date:** [September 20, 2023, 2:04pm UTC](https://discourse.julialang.org/t/matplotlib-rcparams-in-module-init-function-segfault-on-m1/103314/6 "2023-09-20T14:04:38Z")

</div>

> [@cjdoris](#):
>
> @stevengj why does PythonPlot do this?

It was to work around [`using PyPlot` crashes package precompilation on Julia v1.10.0-beta1 · Issue #572 · JuliaPy/PyPlot.jl · GitHub](https://github.com/JuliaPy/PyPlot.jl/issues/572), IIRC. Probably there is a better fix, e.g. initialize matplotlib with a non-interactive backend (Agg) when precompiling.
