3. Coding basics

You need a basic knowledge of python to understand this section. You can find more information on Python at http://python.org/.

To use the built-in python module on cssed scripts, you need to import it as you do with any other python module.


import cssed
		

Once you imported the cssed module you can access all methods in the python API thought the cssed object.


import cssed

cssed.output_write("Hi from python !")
		

The cssed's python API have been made through bindings to cssed's pluggable interface, and - as in the later - all actions take place in the currently opened document. You can switch between documents, to change the current one, but actions - such as add_text() - will happen in the current one.

3.1. Interpreter scope (important)

Once you load the python plugin, all scripts are executed in different environments, and will share no objects between them. There's a complete isolation on the interpreter scope.

You can however run various scripts in the same context, and let them share all globals between them. To accomplish with this you must avoid the interpreter to finalize when it ends to run one script.

If you don't need this feature, and you won't use PyGtk, you can skip the entire section. If you'd like to run PyGtk, you must read the section "Interpreter Reference count - How to hold a interpreter instance".

When using PyGTK is mandatory to hold an interpreter instance.

3.2. Interpreter Reference count - How to hold a interpreter instance.

The flow of cssed's python interpreter is quite easy:

This is enough for most scripts but it will fail on some scenarios as PyGtk applications.

PyGtk applications will be still alive when the interpreter ends to parse and execute the code - as they "live" in cssed's gtk main loop - and the interpreter finalization will have unexpected results. It can even lead in segfaults.

To fit on this scenario, cssed python plugin implements a simple solution. It adds a reference count to the interpreter so it won't finalize meanwhile the reference count does not reaches zero. This have side effects as it won't initialize a new interpreter instance if there is an instance running so more than one scripts can be run in the same environment.

Pseudo code explaining this should be like:


1 If Script Exists :
2  	If Reference Count is 0:
3		Initialize Interpreter
4	Open File
5	Feed File Into Interpreter
6	If Reference Count is 0:
7		Finalize Interpreter
			

To hold the interpreter instance running, you must own a reference to it - so increase the reference count - with the method interpreter_ref(). When you finish with your script you must decrease the reference count with the method interpreter_decref(). You can know how many reference exists in the current interpreter instance with the method interpreter_refcount().

Both interpreter_ref() and interpreter_decref() returns the reference count, after it's increased or decreased.


import pygtk
pygtk.require('2.0')
import gtk
import cssed

class TestDialog:
	def delete_event(self, widget, event, data=None):
		widget.destroy()
		cssed.output_write("Widget destroyed ref count is %d" % cssed.interpreter_decref())
		return gtk.TRUE
	
	def __init__(self):		
		dialog = gtk.Dialog()	
		dialog.connect("delete_event", self.delete_event)
		dialog.set_border_width(2)
		dialog.set_size_request(200,200)
		dialog.set_position(gtk.WIN_POS_CENTER)
		
		# main vbox elements
		label = gtk.Label("Hi from python")
		dialog.vbox.add(label)
		dialog.show_all()
	
TestDialog()
cssed.output_write("Code parsed ref count is %d" % cssed.interpreter_ref())
			

Note: The interpreter will not finalize when the reference count reaches zero in PyGtk scripts, but when the reference count reaches zero and a new script is feed to the interpreter. This is done this way because I found undesirable results when finalizing the interpreter from within pygtk code. It may change in future implementations If I find a safest method to finalize the interpreter.

Meanwhile reference count is greater than zero, all scripts will share the same interpreter instance. If you define a variable in one script it will still be accessible to other scripts run in the same context. If you're going to run an interpreter instance during a long time, to avoid to fill memory each time you run your scripts, you may dispose all allocated objects that are not in use anymore. Meanwhile it can seem a difficult task, it's quite normal in many programming languages.

To make this task easier you can use various techniques, put all variables in a python dictionary and release it when you're done, put all programming and variables into a class and release both the class and instance when you're done, put all variables in a list and release them when you're done.

You can also use python facilities to call the built-in garbage collector.


import gc
import cssed

cssed.output_write("Python garbage collector run: Unreachable objects %d." % gc.collect())
			

In the other hand, this scenario - really long living interpreters - is not meant to be reached but in the case of really specialized setups. Most scripts will hold the interpreter a few miliseconds, PyGtk scripts should hold the interpreter meanwhile the user interface is visible. It's discouraged to built cssed python scripts that should live the same amount of time as the cssed's session. If you have this need it's much better to write a cssed plugin in C. Once you learned the python interface, you know quite well the plugin's one as they're almost the same.

3.3. Sharing data between various scripts

Reference counting - while it was primarily made to be used with PyGtk - can serve to share data among various scripts. An example scenarios may be to run a script to collect data, while using various scripts to manage this data.

Note: You must use this feature with caution and instruct your users to avoid to run other scripts meanwhile they're using yours, as other scripts can change the data. Just have this in mind when you use reference counting, and try to use unique object names, to avoid your scripts to fail silently.

When you hold a reference count, the interpreter will still be alive until it reaches zero and a new script is run, so the collect/hold data script should be something like:


import cssed

some_data = ['hi', 'this', 'is', 'some', 'data']
cssed.interpreter_ref() # don't let the interpreter finalize
			

From this point - as you hold a reference - the interpreter will be alive so any other script can access this data.


import cssed

try:
	for item in some_data:
		cssed.output_write(item)
	cssed.interpreter_decref() # We're done so decrease reference count
except NameError:
	cssed.output_write( "Data is not available" )
			

If you run this script two times, the first will access the data and and decrease the reference count, so the second time you'll be in a new interpreter and the object "some_data" will not be available.

Warning

There'll be of course a problems if you run this script two times and there's any other script holding a reference. As there's another script holding the reference, the second time you run this script, the try statement will work and this script will decrease two times the reference count - one in each run - releasing the reference owned by the other script. This is the reason why it's discouraged to use this technique, but in the event you'll teach your users this can happen, and guide them to avoid to run other scripts meanwhile they're working with this kind of code. There're also other programming technics that may help you to avoid problems. As example to set a global flag for your script to avoid to decrease the reference count but the times it have been increased by the script.

3.4. PyGtk 2.0

You can use all the power of gtk+-2.0 - through pygtk - in cssed python scripts, meanwhile you accomplish the following:

Note: If you have no time to read the section "Interpreter Reference count - How to hold an interpreter instance", or it looks boring or dense to you, you must at least follow this blindly: at script start before to show your main widget you must call cssed.interpreter_ref(), and at script end as soon as you destroy your main widget you must call cssed.interpreter_decref(). Read this section to the end of it, specially the part about gtk.main() and brothers, or expect cssed to fail badly.

About the use of gtk.main(), gtk.main_quit() or sys.exit(), you must avoid them, and code as if you were writing a PyGtk dialog, for an existing PyGtk program.

Warning

Using gtk.main() on cssed scripts may cause segfaults on exit, and calling gtk.main_quit() or sys.exit() will close cssed without warning.

To use gtk dialogs or windows on a cssed python script, just create the widget and show it. To exit simply destroy all the widgets you created - so destroy the top level widget on your user interface hierarchy.


import cssed
import pygtk
pygtk.require('2.0')
import gtk

class TestWindow:
	def delete_event(self, widget, event, data=None):
		widget.destroy()
		cssed.interpreter_decref()
		return gtk.TRUE
	
	def __init__(self):		
		window = gtk.Window(gtk.WINDOW_TOPLEVEL)	
		window.connect("delete_event", self.delete_event)
		window.set_border_width(2)
		window.set_size_request(400,400)
		window.set_position(gtk.WIN_POS_CENTER)
		
		# main vbox elements
		label = gtk.Label("Hi")
		window.add(label)
		window.show_all()

cssed.interpreter_ref()
TestWindow()