Skip to content

kojix2/crython

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

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

  • You need Python3. Python3.12 or later is recommended.
  • Make sure python3-config --ldflags works.

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

  • Use obj.call("Abc") to call a Python attribute whose name is not a valid Crystal method name.
  • Use obj.call("Abc", arg1, arg2) to call it with positional arguments.
  • Use "-".to_py.attr("join") to get a function attribute.
  • Use Crython.slice_full instead of :.

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

  • Symbol conversion: Crystal cannot create Symbols at runtime, so Python strings cannot be converted to Crystal Symbols.
  • Union types: Converting Python collections with mixed types to Crystal collections with union types is not fully supported.

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

About

Crystal meets Python

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • Crystal 97.8%
  • Makefile 2.2%