OpenMediaLib User and Development Guide

Python

So far, we have introduced a number of building blocks which OML provides and the theory on which they operate. You'll probably have noticed that the docs so far are light on example code – focus has been on the 'what' and 'why' as opposed to the 'how'.

Python presents its own set of complications with regard to the 'how' and the two major issues are discussed in this section – both of them should shed some light on some low level details which should to be understood (or at the very least, accepted).

In truth, neither issue have any baring on this document, and really should form an appendix entry, or even better, be documented elsewhere entirely, but they are necessary to know and need to be included somewhere...

When Python imports a module which is provided as a shared object (such as openmedialib) it needs to ensure that all symbols from that library and its dependencies are 'globally exported'. In other words, subsequently loaded modules share the same instance.

The reason for this is simply related to the linking mechanism employed throughout the openlibraries – plugins assume that the libraries required to drive the plugin will be loaded into the hosting application prior to the load of the plugin itself – hence, many symbols are resolved at run time and not at compile time.

On *nix systems which support the dlopen family of functions, this is simply resolved by ensuring that all dynamically loaded libraries export their symbols globally – and this is achieved by ensuring that the RTLD_GLOBAL flag is passed on the dlopen invocation.

You have two options – you can either use:

import openlibraries

TODO: this is currently done via the duplicated 'bootstrap.py' script – an openlibraries module supplied and installed by olibs itself seems better to me. Or a package hierarchy could be introduced (openlibraries.bootstrap for example) and the relevant calls can be made in the __init__.py file.

Alternatively, you can use the following Python snippet directly:

import platform
import sys
import os.path

if platform.system( ) == "Linux":
	try:
		import dl
		sys.setdlopenflags( dl.RTLD_LAZY | dl.RTLD_GLOBAL )
	except:
		sys.setdlopenflags( 257 )

The lazy/now thing isn't very important, but the global is.

Note that this specifically a Linux issue at this point, though other systems may suffer similar issues – OS/X doesn't, but then the dl family is not native to OS/X and their (or Python's) implementation satisfies the requirement by default, as does Win32.

Either way, this must be executed as the first step of any Python script (note – script – not module) – before any other openlibrary (or jahwidgets) related component is imported.

NB: It is easier to say 'do it before anything olib oriented, without exception' than to explain where the exceptions might apply. You have been warned :-).

The second major issue is related to threading.

Python is not thread safe.

This is an odd thing, since Python itself provides fairly comprehensive threading capabilities. However, the threads never run in parallel – other threads are blocked during the execution of any individual python statement.

The consequence of this relates specifically to the callback mechanism which OML provides – this mechanism allows per frame manipulations of properties for each node in the graph. As shall be described, OML provides thread support – and these threads can be placed anywhere in the graph [though there are other restrictions], but if this is employed then the callback into python would fail – to accommodate flexible graph building, the thread safety of a particular sub graph is ascertained prior to the start of the thread – if it contains a python callback, then the thread is not started and the node becomes a no op.

In other words, it will gracefully ignore the threading request if a non-thread safe callback is employed. Doing otherwise would result in 'undefined' behaviour (anything from a crash to a dead lock to unpredictable results would ensue).

OML does its best to protect the application developer from the 'undefined', but it is incumbent on the application developer to ensure that they get the results they want.