1Lupa
2====
3
4.. image:: logo/logo-220x200.png
5
6Lupa integrates the runtimes of Lua_ or LuaJIT2_ into CPython.
7It is a partial rewrite of LunaticPython_ in Cython_ with some
8additional features such as proper coroutine support.
9
10.. _Lua: http://lua.org/
11.. _LuaJIT2: http://luajit.org/
12.. _LunaticPython: http://labix.org/lunatic-python
13.. _Cython: http://cython.org
14
15For questions not answered here, please contact the `Lupa mailing list`_.
16
17.. _`Lupa mailing list`: http://www.freelists.org/list/lupa-dev
18
19.. contents:: :local:
20
21
22Major features
23--------------
24
25* separate Lua runtime states through a ``LuaRuntime`` class
26
27* Python coroutine wrapper for Lua coroutines
28
29* iteration support for Python objects in Lua and Lua objects in
30  Python
31
32* proper encoding and decoding of strings (configurable per runtime,
33  UTF-8 by default)
34
35* frees the GIL and supports threading in separate runtimes when
36  calling into Lua
37
38* tested with Python 2.7/3.5 and later
39
40* written for LuaJIT2 (tested with LuaJIT 2.0.2), but also works
41  with the normal Lua interpreter (5.1 and later)
42
43* easy to hack on and extend as it is written in Cython, not C
44
45
46Why the name?
47-------------
48
49In Latin, "lupa" is a female wolf, as elegant and wild as it sounds.
50If you don't like this kind of straight forward allegory to an
51endangered species, you may also happily assume it's just an
52amalgamation of the phonetic sounds that start the words "Lua" and
53"Python", two from each to keep the balance.
54
55
56Why use it?
57-----------
58
59It complements Python very well.  Lua is a language as dynamic as
60Python, but LuaJIT compiles it to very fast machine code, sometimes
61faster than many statically compiled languages for computational code.
62The language runtime is very small and carefully designed for
63embedding.  The complete binary module of Lupa, including a statically
64linked LuaJIT2 runtime, only weighs some 700KB on a 64 bit machine.
65With standard Lua 5.1, it's less than 400KB.
66
67However, the Lua ecosystem lacks many of the batteries that Python
68readily includes, either directly in its standard library or as third
69party packages. This makes real-world Lua applications harder to write
70than equivalent Python applications. Lua is therefore not commonly
71used as primary language for large applications, but it makes for a
72fast, high-level and resource-friendly backup language inside of
73Python when raw speed is required and the edit-compile-run cycle of
74binary extension modules is too heavy and too static for agile
75development or hot-deployment.
76
77Lupa is a very fast and thin wrapper around Lua or LuaJIT.  It makes it
78easy to write dynamic Lua code that accompanies dynamic Python code by
79switching between the two languages at runtime, based on the tradeoff
80between simplicity and speed.
81
82
83Examples
84--------
85
86..
87      ## doctest helpers:
88      >>> try: _ = sorted
89      ... except NameError:
90      ...     def sorted(seq):
91      ...         l = list(seq)
92      ...         l.sort()
93      ...         return l
94
95.. code:: python
96
97      >>> import lupa
98      >>> from lupa import LuaRuntime
99      >>> lua = LuaRuntime(unpack_returned_tuples=True)
100
101      >>> lua.eval('1+1')
102      2
103
104      >>> lua_func = lua.eval('function(f, n) return f(n) end')
105
106      >>> def py_add1(n): return n+1
107      >>> lua_func(py_add1, 2)
108      3
109
110      >>> lua.eval('python.eval(" 2 ** 2 ")') == 4
111      True
112      >>> lua.eval('python.builtins.str(4)') == '4'
113      True
114
115The function ``lua_type(obj)`` can be used to find out the type of a
116wrapped Lua object in Python code, as provided by Lua's ``type()``
117function:
118
119.. code:: python
120
121      >>> lupa.lua_type(lua_func)
122      'function'
123      >>> lupa.lua_type(lua.eval('{}'))
124      'table'
125
126To help in distinguishing between wrapped Lua objects and normal
127Python objects, it returns ``None`` for the latter:
128
129.. code:: python
130
131      >>> lupa.lua_type(123) is None
132      True
133      >>> lupa.lua_type('abc') is None
134      True
135      >>> lupa.lua_type({}) is None
136      True
137
138Note the flag ``unpack_returned_tuples=True`` that is passed to create
139the Lua runtime.  It is new in Lupa 0.21 and changes the behaviour of
140tuples that get returned by Python functions.  With this flag, they
141explode into separate Lua values:
142
143.. code:: python
144
145      >>> lua.execute('a,b,c = python.eval("(1,2)")')
146      >>> g = lua.globals()
147      >>> g.a
148      1
149      >>> g.b
150      2
151      >>> g.c is None
152      True
153
154When set to False, functions that return a tuple pass it through to the
155Lua code:
156
157.. code:: python
158
159      >>> non_explode_lua = lupa.LuaRuntime(unpack_returned_tuples=False)
160      >>> non_explode_lua.execute('a,b,c = python.eval("(1,2)")')
161      >>> g = non_explode_lua.globals()
162      >>> g.a
163      (1, 2)
164      >>> g.b is None
165      True
166      >>> g.c is None
167      True
168
169Since the default behaviour (to not explode tuples) might change in a
170later version of Lupa, it is best to always pass this flag explicitly.
171
172
173Python objects in Lua
174---------------------
175
176Python objects are either converted when passed into Lua (e.g.
177numbers and strings) or passed as wrapped object references.
178
179.. code:: python
180
181      >>> wrapped_type = lua.globals().type     # Lua's own type() function
182      >>> wrapped_type(1) == 'number'
183      True
184      >>> wrapped_type('abc') == 'string'
185      True
186
187Wrapped Lua objects get unwrapped when they are passed back into Lua,
188and arbitrary Python objects get wrapped in different ways:
189
190.. code:: python
191
192      >>> wrapped_type(wrapped_type) == 'function'  # unwrapped Lua function
193      True
194      >>> wrapped_type(len) == 'userdata'       # wrapped Python function
195      True
196      >>> wrapped_type([]) == 'userdata'        # wrapped Python object
197      True
198
199Lua supports two main protocols on objects: calling and indexing.  It
200does not distinguish between attribute access and item access like
201Python does, so the Lua operations ``obj[x]`` and ``obj.x`` both map
202to indexing.  To decide which Python protocol to use for Lua wrapped
203objects, Lupa employs a simple heuristic.
204
205Pratically all Python objects allow attribute access, so if the object
206also has a ``__getitem__`` method, it is preferred when turning it
207into an indexable Lua object.  Otherwise, it becomes a simple object
208that uses attribute access for indexing from inside Lua.
209
210Obviously, this heuristic will fail to provide the required behaviour
211in many cases, e.g. when attribute access is required to an object
212that happens to support item access.  To be explicit about the
213protocol that should be used, Lupa provides the helper functions
214``as_attrgetter()`` and ``as_itemgetter()`` that restrict the view on
215an object to a certain protocol, both from Python and from inside
216Lua:
217
218.. code:: python
219
220      >>> lua_func = lua.eval('function(obj) return obj["get"] end')
221      >>> d = {'get' : 'value'}
222
223      >>> value = lua_func(d)
224      >>> value == d['get'] == 'value'
225      True
226
227      >>> value = lua_func( lupa.as_itemgetter(d) )
228      >>> value == d['get'] == 'value'
229      True
230
231      >>> dict_get = lua_func( lupa.as_attrgetter(d) )
232      >>> dict_get == d.get
233      True
234      >>> dict_get('get') == d.get('get') == 'value'
235      True
236
237      >>> lua_func = lua.eval(
238      ...     'function(obj) return python.as_attrgetter(obj)["get"] end')
239      >>> dict_get = lua_func(d)
240      >>> dict_get('get') == d.get('get') == 'value'
241      True
242
243Note that unlike Lua function objects, callable Python objects support
244indexing in Lua:
245
246.. code:: python
247
248      >>> def py_func(): pass
249      >>> py_func.ATTR = 2
250
251      >>> lua_func = lua.eval('function(obj) return obj.ATTR end')
252      >>> lua_func(py_func)
253      2
254      >>> lua_func = lua.eval(
255      ...     'function(obj) return python.as_attrgetter(obj).ATTR end')
256      >>> lua_func(py_func)
257      2
258      >>> lua_func = lua.eval(
259      ...     'function(obj) return python.as_attrgetter(obj)["ATTR"] end')
260      >>> lua_func(py_func)
261      2
262
263
264Iteration in Lua
265----------------
266
267Iteration over Python objects from Lua's for-loop is fully supported.
268However, Python iterables need to be converted using one of the
269utility functions which are described here.  This is similar to the
270functions like ``pairs()`` in Lua.
271
272To iterate over a plain Python iterable, use the ``python.iter()``
273function.  For example, you can manually copy a Python list into a Lua
274table like this:
275
276.. code:: python
277
278      >>> lua_copy = lua.eval('''
279      ...     function(L)
280      ...         local t, i = {}, 1
281      ...         for item in python.iter(L) do
282      ...             t[i] = item
283      ...             i = i + 1
284      ...         end
285      ...         return t
286      ...     end
287      ... ''')
288
289      >>> table = lua_copy([1,2,3,4])
290      >>> len(table)
291      4
292      >>> table[1]   # Lua indexing
293      1
294
295Python's ``enumerate()`` function is also supported, so the above
296could be simplified to:
297
298.. code:: python
299
300      >>> lua_copy = lua.eval('''
301      ...     function(L)
302      ...         local t = {}
303      ...         for index, item in python.enumerate(L) do
304      ...             t[ index+1 ] = item
305      ...         end
306      ...         return t
307      ...     end
308      ... ''')
309
310      >>> table = lua_copy([1,2,3,4])
311      >>> len(table)
312      4
313      >>> table[1]   # Lua indexing
314      1
315
316For iterators that return tuples, such as ``dict.iteritems()``, it is
317convenient to use the special ``python.iterex()`` function that
318automatically explodes the tuple items into separate Lua arguments:
319
320.. code:: python
321
322      >>> lua_copy = lua.eval('''
323      ...     function(d)
324      ...         local t = {}
325      ...         for key, value in python.iterex(d.items()) do
326      ...             t[key] = value
327      ...         end
328      ...         return t
329      ...     end
330      ... ''')
331
332      >>> d = dict(a=1, b=2, c=3)
333      >>> table = lua_copy( lupa.as_attrgetter(d) )
334      >>> table['b']
335      2
336
337Note that accessing the ``d.items`` method from Lua requires passing
338the dict as ``attrgetter``.  Otherwise, attribute access in Lua would
339use the ``getitem`` protocol of Python dicts and look up ``d['items']``
340instead.
341
342
343None vs. nil
344------------
345
346While ``None`` in Python and ``nil`` in Lua differ in their semantics, they
347usually just mean the same thing: no value.  Lupa therefore tries to map one
348directly to the other whenever possible:
349
350.. code:: python
351
352      >>> lua.eval('nil') is None
353      True
354      >>> is_nil = lua.eval('function(x) return x == nil end')
355      >>> is_nil(None)
356      True
357
358The only place where this cannot work is during iteration, because Lua
359considers a ``nil`` value the termination marker of iterators.  Therefore,
360Lupa special cases ``None`` values here and replaces them by a constant
361``python.none`` instead of returning ``nil``:
362
363.. code:: python
364
365      >>> _ = lua.require("table")
366      >>> func = lua.eval('''
367      ...     function(items)
368      ...         local t = {}
369      ...         for value in python.iter(items) do
370      ...             table.insert(t, value == python.none)
371      ...         end
372      ...         return t
373      ...     end
374      ... ''')
375
376      >>> items = [1, None ,2]
377      >>> list(func(items).values())
378      [False, True, False]
379
380Lupa avoids this value escaping whenever it's obviously not necessary.
381Thus, when unpacking tuples during iteration, only the first value will
382be subject to ``python.none`` replacement, as Lua does not look at the
383other items for loop termination anymore.  And on ``enumerate()``
384iteration, the first value is known to be always a number and never None,
385so no replacement is needed.
386
387.. code:: python
388
389      >>> func = lua.eval('''
390      ...     function(items)
391      ...         for a, b, c, d in python.iterex(items) do
392      ...             return {a == python.none, a == nil,   -->  a == python.none
393      ...                     b == python.none, b == nil,   -->  b == nil
394      ...                     c == python.none, c == nil,   -->  c == nil
395      ...                     d == python.none, d == nil}   -->  d == nil ...
396      ...         end
397      ...     end
398      ... ''')
399
400      >>> items = [(None, None, None, None)]
401      >>> list(func(items).values())
402      [True, False, False, True, False, True, False, True]
403
404      >>> items = [(None, None)]   # note: no values for c/d => nil in Lua
405      >>> list(func(items).values())
406      [True, False, False, True, False, True, False, True]
407
408
409Note that this behaviour changed in Lupa 1.0.  Previously, the ``python.none``
410replacement was done in more places, which made it not always very predictable.
411
412
413Lua Tables
414----------
415
416Lua tables mimic Python's mapping protocol.  For the special case of
417array tables, Lua automatically inserts integer indices as keys into
418the table.  Therefore, indexing starts from 1 as in Lua instead of 0
419as in Python.  For the same reason, negative indexing does not work.
420It is best to think of Lua tables as mappings rather than arrays, even
421for plain array tables.
422
423.. code:: python
424
425      >>> table = lua.eval('{10,20,30,40}')
426      >>> table[1]
427      10
428      >>> table[4]
429      40
430      >>> list(table)
431      [1, 2, 3, 4]
432      >>> list(table.values())
433      [10, 20, 30, 40]
434      >>> len(table)
435      4
436
437      >>> mapping = lua.eval('{ [1] = -1 }')
438      >>> list(mapping)
439      [1]
440
441      >>> mapping = lua.eval('{ [20] = -20; [3] = -3 }')
442      >>> mapping[20]
443      -20
444      >>> mapping[3]
445      -3
446      >>> sorted(mapping.values())
447      [-20, -3]
448      >>> sorted(mapping.items())
449      [(3, -3), (20, -20)]
450
451      >>> mapping[-3] = 3     # -3 used as key, not index!
452      >>> mapping[-3]
453      3
454      >>> sorted(mapping)
455      [-3, 3, 20]
456      >>> sorted(mapping.items())
457      [(-3, 3), (3, -3), (20, -20)]
458
459To simplify the table creation from Python, the ``LuaRuntime`` comes with
460a helper method that creates a Lua table from Python arguments:
461
462.. code:: python
463
464      >>> t = lua.table(1, 2, 3, 4)
465      >>> lupa.lua_type(t)
466      'table'
467      >>> list(t)
468      [1, 2, 3, 4]
469
470      >>> t = lua.table(1, 2, 3, 4, a=1, b=2)
471      >>> t[3]
472      3
473      >>> t['b']
474      2
475
476A second helper method, ``.table_from()``, is new in Lupa 1.1 and accepts
477any number of mappings and sequences/iterables as arguments.  It collects
478all values and key-value pairs and builds a single Lua table from them.
479Any keys that appear in multiple mappings get overwritten with their last
480value (going from left to right).
481
482.. code:: python
483
484      >>> t = lua.table_from([1, 2, 3], {'a': 1, 'b': 2}, (4, 5), {'b': 42})
485      >>> t['b']
486      42
487      >>> t[5]
488      5
489
490A lookup of non-existing keys or indices returns None (actually ``nil``
491inside of Lua).  A lookup is therefore more similar to the ``.get()``
492method of Python dicts than to a mapping lookup in Python.
493
494.. code:: python
495
496      >>> table[1000000] is None
497      True
498      >>> table['no such key'] is None
499      True
500      >>> mapping['no such key'] is None
501      True
502
503Note that ``len()`` does the right thing for array tables but does not
504work on mappings:
505
506.. code:: python
507
508      >>> len(table)
509      4
510      >>> len(mapping)
511      0
512
513This is because ``len()`` is based on the ``#`` (length) operator in
514Lua and because of the way Lua defines the length of a table.
515Remember that unset table indices always return ``nil``, including
516indices outside of the table size.  Thus, Lua basically looks for an
517index that returns ``nil`` and returns the index before that.  This
518works well for array tables that do not contain ``nil`` values, gives
519barely predictable results for tables with 'holes' and does not work
520at all for mapping tables.  For tables with both sequential and
521mapping content, this ignores the mapping part completely.
522
523Note that it is best not to rely on the behaviour of len() for
524mappings.  It might change in a later version of Lupa.
525
526Similar to the table interface provided by Lua, Lupa also supports
527attribute access to table members:
528
529.. code:: python
530
531      >>> table = lua.eval('{ a=1, b=2 }')
532      >>> table.a, table.b
533      (1, 2)
534      >>> table.a == table['a']
535      True
536
537This enables access to Lua 'methods' that are associated with a table,
538as used by the standard library modules:
539
540.. code:: python
541
542      >>> string = lua.eval('string')    # get the 'string' library table
543      >>> print( string.lower('A') )
544      a
545
546
547Python Callables
548----------------
549
550As discussed earlier, Lupa allows Lua scripts to call Python functions
551and methods:
552
553.. code:: python
554
555      >>> def add_one(num):
556      ...     return num + 1
557      >>> lua_func = lua.eval('function(num, py_func) return py_func(num) end')
558      >>> lua_func(48, add_one)
559      49
560
561      >>> class MyClass():
562      ...     def my_method(self):
563      ...         return 345
564      >>> obj = MyClass()
565      >>> lua_func = lua.eval('function(py_obj) return py_obj:my_method() end')
566      >>> lua_func(obj)
567      345
568
569Lua doesn't have a dedicated syntax for named arguments, so by default
570Python callables can only be called using positional arguments.
571
572A common pattern for implementing named arguments in Lua is passing them
573in a table as the first and only function argument.  See
574http://lua-users.org/wiki/NamedParameters for more details.  Lupa supports
575this pattern by providing two decorators: ``lupa.unpacks_lua_table``
576for Python functions and ``lupa.unpacks_lua_table_method`` for methods
577of Python objects.
578
579Python functions/methods wrapped in these decorators can be called from
580Lua code as ``func(foo, bar)``, ``func{foo=foo, bar=bar}``
581or ``func{foo, bar=bar}``.  Example:
582
583.. code:: python
584
585      >>> @lupa.unpacks_lua_table
586      ... def add(a, b):
587      ...     return a + b
588      >>> lua_func = lua.eval('function(a, b, py_func) return py_func{a=a, b=b} end')
589      >>> lua_func(5, 6, add)
590      11
591      >>> lua_func = lua.eval('function(a, b, py_func) return py_func{a, b=b} end')
592      >>> lua_func(5, 6, add)
593      11
594
595If you do not control the function implementation, you can also just
596manually wrap a callable object when passing it into Lupa:
597
598.. code:: python
599
600      >>> import operator
601      >>> wrapped_py_add = lupa.unpacks_lua_table(operator.add)
602
603      >>> lua_func = lua.eval('function(a, b, py_func) return py_func{a, b} end')
604      >>> lua_func(5, 6, wrapped_py_add)
605      11
606
607There are some limitations:
608
6091. Avoid using ``lupa.unpacks_lua_table`` and ``lupa.unpacks_lua_table_method``
610   for functions where the first argument can be a Lua table.  In this case
611   ``py_func{foo=bar}`` (which is the same as ``py_func({foo=bar})`` in Lua)
612   becomes ambiguous: it could mean either "call ``py_func`` with a named
613   ``foo`` argument" or "call ``py_func`` with a positional ``{foo=bar}``
614   argument".
615
6162. One should be careful with passing ``nil`` values to callables wrapped in
617   ``lupa.unpacks_lua_table`` or ``lupa.unpacks_lua_table_method`` decorators.
618   Depending on the context, passing ``nil`` as a parameter can mean either
619   "omit a parameter" or "pass None".  This even depends on the Lua version.
620
621   It is possible to use ``python.none`` instead of ``nil`` to pass None values
622   robustly.  Arguments with ``nil`` values are also fine when standard braces
623   ``func(a, b, c)`` syntax is used.
624
625Because of these limitations lupa doesn't enable named arguments for all
626Python callables automatically.  Decorators allow to enable named arguments
627on a per-callable basis.
628
629
630Lua Coroutines
631--------------
632
633The next is an example of Lua coroutines.  A wrapped Lua coroutine
634behaves exactly like a Python coroutine.  It needs to get created at
635the beginning, either by using the ``.coroutine()`` method of a
636function or by creating it in Lua code.  Then, values can be sent into
637it using the ``.send()`` method or it can be iterated over.  Note that
638the ``.throw()`` method is not supported, though.
639
640.. code:: python
641
642      >>> lua_code = '''\
643      ...     function(N)
644      ...         for i=0,N do
645      ...             coroutine.yield( i%2 )
646      ...         end
647      ...     end
648      ... '''
649      >>> lua = LuaRuntime()
650      >>> f = lua.eval(lua_code)
651
652      >>> gen = f.coroutine(4)
653      >>> list(enumerate(gen))
654      [(0, 0), (1, 1), (2, 0), (3, 1), (4, 0)]
655
656An example where values are passed into the coroutine using its
657``.send()`` method:
658
659.. code:: python
660
661      >>> lua_code = '''\
662      ...     function()
663      ...         local t,i = {},0
664      ...         local value = coroutine.yield()
665      ...         while value do
666      ...             t[i] = value
667      ...             i = i + 1
668      ...             value = coroutine.yield()
669      ...         end
670      ...         return t
671      ...     end
672      ... '''
673      >>> f = lua.eval(lua_code)
674
675      >>> co = f.coroutine()   # create coroutine
676      >>> co.send(None)        # start coroutine (stops at first yield)
677
678      >>> for i in range(3):
679      ...     co.send(i*2)
680
681      >>> mapping = co.send(None)   # loop termination signal
682      >>> sorted(mapping.items())
683      [(0, 0), (1, 2), (2, 4)]
684
685It also works to create coroutines in Lua and to pass them back into
686Python space:
687
688.. code:: python
689
690      >>> lua_code = '''\
691      ...   function f(N)
692      ...         for i=0,N do
693      ...             coroutine.yield( i%2 )
694      ...         end
695      ...   end ;
696      ...   co1 = coroutine.create(f) ;
697      ...   co2 = coroutine.create(f) ;
698      ...
699      ...   status, first_result = coroutine.resume(co2, 2) ;   -- starting!
700      ...
701      ...   return f, co1, co2, status, first_result
702      ... '''
703
704      >>> lua = LuaRuntime()
705      >>> f, co, lua_gen, status, first_result = lua.execute(lua_code)
706
707      >>> # a running coroutine:
708
709      >>> status
710      True
711      >>> first_result
712      0
713      >>> list(lua_gen)
714      [1, 0]
715      >>> list(lua_gen)
716      []
717
718      >>> # an uninitialised coroutine:
719
720      >>> gen = co(4)
721      >>> list(enumerate(gen))
722      [(0, 0), (1, 1), (2, 0), (3, 1), (4, 0)]
723
724      >>> gen = co(2)
725      >>> list(enumerate(gen))
726      [(0, 0), (1, 1), (2, 0)]
727
728      >>> # a plain function:
729
730      >>> gen = f.coroutine(4)
731      >>> list(enumerate(gen))
732      [(0, 0), (1, 1), (2, 0), (3, 1), (4, 0)]
733
734
735Threading
736---------
737
738The following example calculates a mandelbrot image in parallel
739threads and displays the result in PIL. It is based on a `benchmark
740implementation`_ for the `Computer Language Benchmarks Game`_.
741
742.. _`Computer Language Benchmarks Game`: http://shootout.alioth.debian.org/u64/benchmark.php?test=all&lang=luajit&lang2=python3
743.. _`benchmark implementation`: http://shootout.alioth.debian.org/u64/program.php?test=mandelbrot&lang=luajit&id=1
744
745.. code:: python
746
747    lua_code = '''\
748        function(N, i, total)
749            local char, unpack = string.char, table.unpack
750            local result = ""
751            local M, ba, bb, buf = 2/N, 2^(N%8+1)-1, 2^(8-N%8), {}
752            local start_line, end_line = N/total * (i-1), N/total * i - 1
753            for y=start_line,end_line do
754                local Ci, b, p = y*M-1, 1, 0
755                for x=0,N-1 do
756                    local Cr = x*M-1.5
757                    local Zr, Zi, Zrq, Ziq = Cr, Ci, Cr*Cr, Ci*Ci
758                    b = b + b
759                    for i=1,49 do
760                        Zi = Zr*Zi*2 + Ci
761                        Zr = Zrq-Ziq + Cr
762                        Ziq = Zi*Zi
763                        Zrq = Zr*Zr
764                        if Zrq+Ziq > 4.0 then b = b + 1; break; end
765                    end
766                    if b >= 256 then p = p + 1; buf[p] = 511 - b; b = 1; end
767                end
768                if b ~= 1 then p = p + 1; buf[p] = (ba-b)*bb; end
769                result = result .. char(unpack(buf, 1, p))
770            end
771            return result
772        end
773    '''
774
775    image_size = 1280   # == 1280 x 1280
776    thread_count = 8
777
778    from lupa import LuaRuntime
779    lua_funcs = [ LuaRuntime(encoding=None).eval(lua_code)
780                  for _ in range(thread_count) ]
781
782    results = [None] * thread_count
783    def mandelbrot(i, lua_func):
784        results[i] = lua_func(image_size, i+1, thread_count)
785
786    import threading
787    threads = [ threading.Thread(target=mandelbrot, args=(i,lua_func))
788                for i, lua_func in enumerate(lua_funcs) ]
789    for thread in threads:
790        thread.start()
791    for thread in threads:
792        thread.join()
793
794    result_buffer = b''.join(results)
795
796    # use Pillow to display the image
797    from PIL import Image
798    image = Image.fromstring('1', (image_size, image_size), result_buffer)
799    image.show()
800
801Note how the example creates a separate ``LuaRuntime`` for each thread
802to enable parallel execution.  Each ``LuaRuntime`` is protected by a
803global lock that prevents concurrent access to it.  The low memory
804footprint of Lua makes it reasonable to use multiple runtimes, but
805this setup also means that values cannot easily be exchanged between
806threads inside of Lua.  They must either get copied through Python
807space (passing table references will not work, either) or use some Lua
808mechanism for explicit communication, such as a pipe or some kind of
809shared memory setup.
810
811
812Restricting Lua access to Python objects
813----------------------------------------
814
815..
816        >>> try: unicode = unicode
817        ... except NameError: unicode = str
818
819Lupa provides a simple mechanism to control access to Python objects.
820Each attribute access can be passed through a filter function as
821follows:
822
823.. code:: python
824
825        >>> def filter_attribute_access(obj, attr_name, is_setting):
826        ...     if isinstance(attr_name, unicode):
827        ...         if not attr_name.startswith('_'):
828        ...             return attr_name
829        ...     raise AttributeError('access denied')
830
831        >>> lua = lupa.LuaRuntime(
832        ...           register_eval=False,
833        ...           attribute_filter=filter_attribute_access)
834        >>> func = lua.eval('function(x) return x.__class__ end')
835        >>> func(lua)
836        Traceback (most recent call last):
837         ...
838        AttributeError: access denied
839
840The ``is_setting`` flag indicates whether the attribute is being read
841or set.
842
843Note that the attributes of Python functions provide access to the
844current ``globals()`` and therefore to the builtins etc.  If you want
845to safely restrict access to a known set of Python objects, it is best
846to work with a whitelist of safe attribute names.  One way to do that
847could be to use a well selected list of dedicated API objects that you
848provide to Lua code, and to only allow Python attribute access to the
849set of public attribute/method names of these objects.
850
851Since Lupa 1.0, you can alternatively provide dedicated getter and
852setter function implementations for a ``LuaRuntime``:
853
854.. code:: python
855
856        >>> def getter(obj, attr_name):
857        ...     if attr_name == 'yes':
858        ...         return getattr(obj, attr_name)
859        ...     raise AttributeError(
860        ...         'not allowed to read attribute "%s"' % attr_name)
861
862        >>> def setter(obj, attr_name, value):
863        ...     if attr_name == 'put':
864        ...         setattr(obj, attr_name, value)
865        ...         return
866        ...     raise AttributeError(
867        ...         'not allowed to write attribute "%s"' % attr_name)
868
869        >>> class X(object):
870        ...     yes = 123
871        ...     put = 'abc'
872        ...     noway = 2.1
873
874        >>> x = X()
875
876        >>> lua = lupa.LuaRuntime(attribute_handlers=(getter, setter))
877        >>> func = lua.eval('function(x) return x.yes end')
878        >>> func(x)  # getting 'yes'
879        123
880        >>> func = lua.eval('function(x) x.put = "ABC"; end')
881        >>> func(x)  # setting 'put'
882        >>> print(x.put)
883        ABC
884        >>> func = lua.eval('function(x) x.noway = 42; end')
885        >>> func(x)  # setting 'noway'
886        Traceback (most recent call last):
887         ...
888        AttributeError: not allowed to write attribute "noway"
889
890
891Importing Lua binary modules
892----------------------------
893
894**This will usually work as is**, but here are the details, in case
895anything goes wrong for you.
896
897To use binary modules in Lua, you need to compile them against the
898header files of the LuaJIT sources that you used to build Lupa, but do
899not link them against the LuaJIT library.
900
901Furthermore, CPython needs to enable global symbol visibility for
902shared libraries before loading the Lupa module.  This can be done by
903calling ``sys.setdlopenflags(flag_values)``.  Importing the ``lupa``
904module will automatically try to set up the correct ``dlopen`` flags
905if it can find the platform specific ``DLFCN`` Python module that
906defines the necessary flag constants.  In that case, using binary
907modules in Lua should work out of the box.
908
909If this setup fails, however, you have to set the flags manually.
910When using the above configuration call, the argument ``flag_values``
911must represent the sum of your system's values for ``RTLD_NEW`` and
912``RTLD_GLOBAL``.  If ``RTLD_NEW`` is 2 and ``RTLD_GLOBAL`` is 256, you
913need to call ``sys.setdlopenflags(258)``.
914
915Assuming that the Lua luaposix_ (``posix``) module is available, the
916following should work on a Linux system:
917
918.. code:: python
919
920      >>> import sys
921      >>> orig_dlflags = sys.getdlopenflags()
922      >>> sys.setdlopenflags(258)
923      >>> import lupa
924      >>> sys.setdlopenflags(orig_dlflags)
925
926      >>> lua = lupa.LuaRuntime()
927      >>> posix_module = lua.require('posix')     # doctest: +SKIP
928
929.. _luaposix: http://git.alpinelinux.org/cgit/luaposix
930
931
932Building with different Lua versions
933------------------------------------
934
935The build is configured to automatically search for an installed version
936of first LuaJIT and then Lua, and failing to find either, to use the bundled
937LuaJIT or Lua version.
938
939If you wish to build Lupa with a specific version of Lua, you can
940configure the following options on setup:
941
942.. list-table::
943   :widths: 20 35
944   :header-rows: 1
945
946   * - Option
947     - Description
948   * - ``--lua-lib <libfile>``
949     - Lua library file path, e.g. ``--lua-lib /usr/local/lib/lualib.a``
950   * - ``--lua-includes <incdir>``
951     - Lua include directory, e.g. ``--lua-includes /usr/local/include``
952   * - ``--use-bundle``
953     - Use bundled LuaJIT or Lua instead of searching for an installed version.
954   * - ``--no-bundle``
955     - Don't use the bundled LuaJIT/Lua, search for an installed version of LuaJIT or Lua,
956       e.g. using ``pkg-config``.
957   * - ``--no-lua-jit``
958     - Don't use or search for LuaJIT, only use or search Lua instead.
959