Crython

test Ask DeepWiki Lines of Code

💎 🐍 Crystal meets Python!

Overview

Crython is a tool that lets you use Python libraries in Crystal, a programming language. It provides seamless integration between Crystal and Python, allowing you to leverage Python's ecosystem while enjoying Crystal language.

Installation

Add this to your dependencies:

dependencies:
  crython:
    github: kojix2/crython

Environment Setup

To find Python libraries, set the LD_LIBRARY_PATH:

export LD_LIBRARY_PATH=$(python3 -c \
"import sysconfig; print(sysconfig.get_config_var('LIBDIR'))"):$LD_LIBRARY_PATH

This command adds the Python library directory to LD_LIBRARY_PATH.

To use Crython in your Crystal project, add this line:

require "crython"

For complex numbers, also add:

require "complex"

Basic Usage

Importing a Python Module

Import a Python module

np = Crython.import("numpy")

Use the module

array = np.array([1, 2, 3])
result = array * 2
puts result  # [2 4 6]

Embedding Python Code

Crython.session do
  # Write your Python code here
  Crython.eval("print('Hello from Python!')")

  # Import modules and use them
  np = Crython.import("numpy")
  array = np.array([1, 2, 3])
  puts array
end

Type Conversion

Crystal to Python

Convert Crystal objects to Python objects using the to_py method:

42.to_py                    # Python int
3.14.to_py                  # Python float
"hello".to_py               # Python str
[1, 2, 3].to_py             # Python list
{"a" => 1, "b" => 2}.to_py  # Python dict
true.to_py                  # Python bool
nil.to_py                   # Python None
Complex.new(1, 2).to_py     # Python complex

Python to Crystal

Convert Python objects to Crystal objects using the to_cr method:

py_int = 42.to_py
py_int.to_cr                         # Int64: 42
py_float = 3.14.to_py
py_float.to_cr                       # Float64: 3.14
py_str = "hello".to_py
py_str.to_cr                         # String: "hello"
py_list = [1, 2, 3].to_py
py_list.to_cr                        # Array(PyObject)
py_dict = {"a" => 1, "b" => 2}.to_py
py_dict.to_cr                        # Hash(PyObject, PyObject)
py_bool = true.to_py
py_bool.to_cr                        # Bool: true
py_none = nil.to_py
py_none.to_cr                        # Nil: nil
py_complex = Complex.new(1, 2).to_py
py_complex.to_cr                     # Complex: 1+2i

You can also convert Python objects to specific Crystal types:

py_list = [1, 2, 3].to_py
Array(Int32).new(py_list)            # Array(Int32): [1, 2, 3]
py_dict = {"a" => 1, "b" => 2}.to_py
Hash(String, Int32).new(py_dict)     # Hash(String, Int32): {"a" => 1, "b" => 2}

Working with Python Objects

Call methods on Python objects

py_str = "hello".to_py
py_str.upper.to_cr  # "HELLO"

Access attributes

np = Crython.import("numpy")
version = np.attr("__version__").to_cr
puts "NumPy version: #{version}"

Call methods with arguments

math = Crython.import("math")
result = math.pow(2, 3).to_cr
puts "2^3 = #{result}"  # 8.0

Call methods with keyword arguments

plt = Crython.import("matplotlib.pyplot")
plt.plot([1, 2, 3], [4, 5, 6], color: "red", marker: "o")

Advanced Usage

Tips

Error Handling

Crython.session do
  begin
    # This will raise an error
    Crython.eval("1/0")
  rescue ex
    puts "Python error: #{ex.message}"
  end
end

Examples

For more examples, check the examples folder. To build all examples, use:

make examples

Then run:

./bin/hello

NumPy Example

Crython.session do
  np = Crython.import("numpy")

  x1 = np.array([1, 2, 3])
  x2 = np.array([4, 5, 6])

  y = x1 + x2
  puts "#{x1} + #{x2} = #{y}"  # [1 2 3] + [4 5 6] = [5 7 9]
end

Matplotlib Example

Crython.session do
  plt = Crython.import("matplotlib.pyplot")

  # Create data
  x = [1, 2, 3, 4, 5]
  y = [1, 4, 9, 16, 25]

  # Create plot
  plt.plot(x, y, marker: "o", linestyle: "--")
  plt.title("Square Numbers")
  plt.xlabel("Number")
  plt.ylabel("Square")

  # Show plot
  plt.show
end

Known Limitations

Building Examples with Custom Python Library

python3-config usually provides the correct flags for linking. If it doesn't, you can manually set LDFLAGS to your environment's library path. For example, if using micromamba:

LDFLAGS="-L/Users/<your-username>/micromamba/envs/crython/lib -lpython3.13" make examples

Replace <your-username> with your actual username and adjust the path as necessary.

Troubleshooting

Library Not Found

If you get an error like error while loading shared libraries: libpython3.13.so.1.0: cannot open shared object file: No such file or directory, make sure you've set the LD_LIBRARY_PATH correctly:

export LD_LIBRARY_PATH=$(python3 -c "import sysconfig; print(sysconfig.get_config_var('LIBDIR'))"):$LD_LIBRARY_PATH

Linking Errors

If you encounter linking errors during compilation, check that python3-config --ldflags returns the correct flags for your Python installation.

Contributing

Fork ➔ Edit ➔ Commit ➔ Pull Request

LICENSE

MIT

Credits

Romain Franceschini - The original creator of the Crython project