Generating and Decoding QRCodes using Python modules from Elixir app The Erlang VM, on which Elixir runs, is efficient for applications in particular domains but falls short when it comes to other operations like data . Python on the other hand, has a rich set of packages for tackling data processing and scientific calculations. processing and computation-heavy stuff Luckily the Erlang VM allows interoperability with other languages using the . Erlang port protocol is a library for Elixir which makes it easier to connect Erlang to a number of other programming languages using the Erlang port protocol. Currently Erlport supports and . ErlPort Python Ruby In this post we’ll see how we can call Python module to generate QRCode right from our Elixir app. **Erlport Python Primer**To use Erlport, just add to your dependencies #mix.exs{:erlport, "~> 0.9"} Once Erlport is added to your project, you have access to module in your elixir code. This Erlport python module allows you to start an Elixir process to execute python code. :_python_ #creates and Elixir process for calling python functions{:ok, pid} = :python.start() #get the current python version:python.call(pid, :sys, :'version.__str__', []) Even better, Erlport allows you to configure python path so you canload custom python modules from a specific directory! #Automatically load all modules in directory with path /custom/modules/directory {:ok, pid} = :python.start([{:python_path, '/custom/modules/directory'}]) With the process returned from calling , you can call functions in your python module using the familiar - , , format start/1 MFA module function argument {:ok, pid} = :python.start([{:python_path, 'custom_modules_directory'}]) = :test #python module to call = :hello # function in module = ["World"] # list of arguments pass to function the functionresult = :python.call(p, module, function, arguments) module function arguments If the python function returns data, it will be bound to variable in the code above. Otherwise returns for python functions that don’t return any data. result :python.call/4 :undefined In this project, we will create a simple app that encode string to QRCode images. Then decode the QRCode image file to get the string back. Instead of using native Elixir/Erlang lib we will call Python module ( ) from our app to do the encoding and decoding. Check to setup qrtools. Let Create The Elixir Project qrtools here 1. Create the Elixir OTP app $ mix new elixir_python_qrcode 2. Add dependency Add to your dependencies erlport mix.exs defp deps do[# {:dep_from_hexpm, "~> 0.3.0"},# {:dep_from_git, git: "https://github.com/elixir-lang/my_dep.git", tag: "0.1.0"}, ,]end {:erlport, "~> 0.9"} Then install project dependencies. $ mix deps.get 3. Lets add wrapper Elixir module for Erlport Create , and add Elixir module called and add these helper functions. lib/helper.ex ElixirPythonQrcode.Helper defmodule ElixirPythonQrcode.Helper do@doc """ Parameters - path: directory to include in python path (charlist) """def python_instance(path) when is_list(path) do{:ok, pid} = :python.start([{:python_path, to_charlist(path)}])pidend def python_instance(_) do{:ok, pid} = :python.start()pidend @doc """Call python function using MFA format"""def call_python(pid, module, function, arguments \\ []) dopid|>:python.call(module, function, arguments) endend 4. Add Module code for the main. We will have two functions — which takes in some string and file path. It encodes the data and write the QRCode image to the given file path, and — which takes in file path to QRCode image and decodes to get original data. encode/2 decode/1 Let’s edit lib/elixir_python_qrcode.ex # lib/elixir_python_qrcode.ex defmodule ElixirPythonQrcode do@moduledoc """Documentation for ElixirPythonQrcode."""alias ElixirPythonQrcode.Helper def encode(data, file_path) docall_python(:qrcode, :encode, [data, file_path])end def decode(file_path) docall_python(:qrcode, :decode, [file_path])end defp default_instance() do#Load all modules in our priv/python directorypath = [:code.priv_dir(:elixir_python_qrcode), "python"]|> Path.join()Helper.python_instance(to_charlist(path))end wrapper function to call python functions using default python instance defp call_python(module, function, args \\ []) dodefault_instance()|> Helper.call_python(module, function, args)end end 5. Now let’s create our python module Create module that will contain our python functions. These functions handle the actual QRCode generation and decoding. priv/python/qrcode.py # priv/python/qrcode.py def decode(file_path):import qrtoolsqr = qrtools.QR()qr.decode(file_path)return qr.data def encode(data, file_path):import qrtoolsqr = qrtools.QR(data.encode("utf-8"))return qr.encode(filename=file_path) Let’s test our code. 6. $ iex -S mixiex(1)> ElixirPythonQrcode.encode("Some test to encode", "qrcode.png")0iex(2)> ElixirPythonQrcode.decode("qrcode.png")'Some test to encode'iex(3)> ElixirPythonQrcode.decode("qrcode.png") |> to_string()"Some test to encode" That’s it. Check out . the github repo Happy coding! Check out for Asynchronous communication between Elixir and Python Part II
Share Your Thoughts