Skipole WSGI generator.

Back to:


Development at Bitbucket:

Skipole Project Documentation Downloads

Associated projects:

pi01 pi02 skitest skiclub svgplot

skipole - getting started

Skipole only requires a single tar file download to a development machine such as a Laptop, where a project is created. The application ultimately produces a project tar file which can be installed on your final target server or Raspberry Pi.

You will need to be able to open a browser on your development machine, so if developing on a Pi, rather than a full laptop, it will need more than just a command line environment.

This article describes setting up an ‘hello world’ web service with an input form where a user can set their name, and the web page updates with ‘hello your-name’. Once that is mastered, you are not far from creating input controls, and responding with whatever data you can generate.

Follow the ‘Downloads’ link on the left to get the latest skipole tar file skipole_1.0.0.tar.gz, download it into a new empty directory on your development machine and then extract it. If on a Pi, within that directory, you would extract with:

tar -xvf skipole_1.0.0.tar.gz

This article assumes the latest version is skipole_1.0.0.tar.gz – if there is a later version then use that.

This will give you a sub directory ‘skipole’ with the application within it. Also create a project directory ‘myproj’, so now you have two directories; ‘myproj’ and ‘skipole’. You could use a name other than myproj, in fact you could have multiple directories with a number of different projects if you wish. Then change into the skipole directory, and if you list the contents you should see:

To create a new project, run


and answer the questions. The first is ‘Yes to proceed?’ - type Yes with a capital Y. It will ask for the name of your new project, myproj and the location of your project directory, ../myproj which is the path to your new myproj directory. When it asks if you wish to copy an existing project, type No.

It will then create further sub-directories and files in your myproj directory, and if you use the browser on your development machine to display localhost:8000 you will see a web page displayed.

You should also view localhost:8000/skiadmin (in a second tab of your browser) to see an administration page. There is one particularly important function: ‘Commit Project’, press this, and any changes made to the project are saved, you will then be able to download the project, which will give you a tar file of your final web service which can be installed on your target web server or Raspberry Pi. Currently it’s not worth doing, as it does no more than serve the welcome page.

Choose the ‘Root Folder’ link on the left, and you will see the folder and page structure created for your project.

Background Concepts

At this point we need to discuss a little bit more about Skipole. If you want to shut it down; at the command line where you ran the program, press CTRL-C to stop it. You may have to do this two or three times to stop it.

To start again do:

python3 myproj
- This starts, without running the skiadmin pages


python3 -s myproj
- This starts, and also serves the skiadmin pages


python3 -h
- This displays command line options.

The tar file you can download after you have commited your project is essentially the skipole package, together with files defining your project, and with the skiadmin development capability removed. It includes a script. So saving the tar file on a Raspberry Pi, extracting it, and running:


will run your web service on the Pi.

As well as you will see the script This creates a WSGI application which can be used with WSGI compatible web servers.

You may want the web service to start automatically, and perhaps with a multithreaded web server rather than the web server built into the Python language. If this is the case, follow the Documentation link on the left navigation panel which leads to the wiki at the bitbucket skipole development site which gives examples.

All that remains is to actually develop your project! So back to the development machine, and the display of your Root Folder contents.

The Root Folder

It consists of pages and folders, which can be edited, created and deleted. The ‘pages’ are of different types, primarily ‘File’ pages – which link to static files under your myproj/projectfiles/static directory, ‘Template’ pages – which act as dynamic HTML pages that contain widgets, and ‘Responders’ which are actually routines, which accept the call to the web site, call your python functions, and then pass the final data on to a ‘Template’ page, setting data into the widgets.

Certain Folders are set as ‘Restricted’. These cannot be called from a browser directly, so typically Template pages will be set into ‘Restricted’ folders, and can only be requested by calling a Responder which in turn can pass the call into the restricted folder.

Initially your new project has a ‘No Operation’ Responder as the index page under the Root Folder, so when ‘localhost:8000’ is called, the call is passed to the No Operation responder which has been set to do nothing more than pass the call to the Template page with ident number 2001. Every folder and page has a unique ident number.

We want the Template page to say ‘hello world’, and to have an input form. So choose the edit button on the line of the table showing page 2001. To the left of the new admin page displayed, you will see buttons with ‘index_template Head’ and ‘index_template Body’.

Choose ‘index_template Body’.

Edit a Template Body

HTML tags and their contents are created here. To start, on the line with a ‘p’ tag, labelled ‘Paragraph of text’, choose the ‘Remove’ button to get rid of the paragraph and the initial welcome message.

The welcome message is actually held in a ‘TextBlock’ rather than set as simple text, a TextBlock being a reference key associated with a block of text – which you can create with the ‘TextBlocks’ option in the left navigation panel. We will not be using them in this article, it is a feature you may want to explore later.

We will be inserting a widget, on the remaining 'body' line, choose ‘Insert’, then ‘Insert a Widget’, and then in the list of modules, choose ‘paras’. This will list widgets in the ‘paras’ module, choose the ‘ParaText’ widget.

In the subsequent form, set a widget name of top_para and a description of ‘top paragraph in the page’, and then choose Submit. This will create the widget. It has four fields, choose the ‘para_text’ field and set a Field value of Hello World, and remember to submit it. You have the option of changing the field name, leave it as ‘para_text’ - we will be using the widgetname and fieldname later, so remember them : (“top_para”, “para_text”).

Choose 'top_para' from the left navigation panel to return to the widget edit page and you should see:

In the browser tab showing the actual project, refresh the page, and you should see “Hello World”.

Back under the skiadmin browser tab, choose ‘index_template Body’ again, and you will see your new widget placed under the ‘body’ tag.

We are now going to append another widget, to display a text input form. So choose the ‘Append’ button, then ‘Append a Widget’, then module ‘inputtext’ and then widget ‘SubmitTextInput1’. Give this widget a name in_form and any description you like and press Submit to create the widget.

Under the ‘action’ field, set a value of 2, this is the ident number of the page which will be called when the form’s submit is pressed. Currently no page exists with this ident, but we are going to make one. First return to the ‘in_form’ edit page by choosing ‘in_form’ on the left, and then go down the fields until you see one called ‘label’. Edit that field to give a value of Type name here:

So your project page will now have an input form - but currently with a broken link, as it has an action of sending the form to page 2, but page 2 does not exist.

We now need to create a Responder, with an ident of 2, that will handle this form when it is submitted.

Create a Responder

Choose Root Folder from the left navigation panel. On the top line of the table, with description ‘Site root’ choose ‘Add Page’.

Choose the radio button ‘Responder’, set a description, something like Handles form input, a new free ident number will be displayed, change this to the number 2, and set a page name of accept_input, then press Submit.

There are multiple Responders available, choose ‘AllowStore’ you can now edit this Responder.

When a form is submitted, the widget includes the calling page ident in the submitted data, however if someone calls the Responder incorrectly, without any ident information, the Responder redirects the call by sending it to an ‘alternate page’.

At ‘Ident or label of alternate page’ set a value of home, to send invalid callers to the home index page. Remember to press Submit.

The ‘label' referred to above is a string of text which is a reference to an ident number. If you prefer to deal with labels rather than numbers, you can assign labels using the ‘Page Labels’ button in the left navigation panel. In this case, the label ‘home’ has been set to the ident of 1, which is the Responder that leads to the home index page.

At ‘Ident or label of target page’ set 2001 to forward the results of this responder to the Template page. 2001 is equivalent to the full page ident of “myproj,2001” as this refers to project myproj, page number 2001. A project can have further ‘sub-projects’ attached, which is why the full ident includes the project name.

At ‘Ident or label of an allowed caller’ also set 2001, because it accepts the data from someone submitting the form in page 2001. Multiple allowed callers can be set, but in this case only one - page 2001 - is relevant.

At ‘Add a widgfield’ set the string in_form, input_text - this informs the Responder it should expect data from the ‘in_form’ widget, from field ‘input_text’, the terminology of ‘widgfield’ is used for this sort of input.


Validation on skipole is normally a two stage affair, when creating a Widget you would add one or more 'validators' to the widget field which is sending data (which would be widget "in_form", field "input_text" in this case), and on the Responder you would enable validation, so when the data is received, the validation test is run.

In this example, for the sake of brevity, we have not added any validators to the widget, so do not enable validation on the Responder, but do enable submit_data. This instructs the responder to call your Python function. Two further fields will appear, do not bother with the ‘Add string to submit_list’ function, however do set home into ‘Ident or label of fail page’.

Be sure to press the appropriate Submit button after changing any field.

Then choose ‘Admin’ from the left navigation panel, and to ensure all your changes are not lost, choose ‘Commit Project’.

Now go to your project page and refresh it. You should see your input form, however if you input data, the page refreshes, but nothing happens. At this point you need to create a Python function.

Your Python functions

Open the file at ../myproj/projectcode/ with a text editor and you will see a number of functions, scroll down until you see the definition of the ‘submit_data’ function, and edit it to read:

def submit_data(caller_ident, ident_list, submit_list, submit_dict, call_data, page_data, lang):
    """This function is called when a Responder wishes to submit data for processing"""
    received_data = call_data['in_form', 'input_text']
    page_data['top_para','para_text'] = "Hello " +  received_data

Save the file. To ensure the project picks up this new function you will need to restart the program. Press CTRL-C a few times at the command window, and then:

python3 -s myproj

Refresh your project tab on the browser and try submitting your name. You should see your name displayed in the top paragraph of the page.

So what has just happened? The AllowStore responder has accepted data submitted from the ‘in_form’ widget, in field ‘input_text’ and has stored it in the call_data dictionary under a key which is tuple (‘in_form’ ,‘input_text’).

It has then called your submit_data function, which has picked the value from call_data, and inserted it (together with an ‘Hello’ string) into the page_data dictionary, with a key of ('top_para','para_text') – this being a tuple which describes the top_para widget, and field para_text.

The Responder then passes the call on to the target Template page, and the page_data dictionary is used to populate widgets and fields, in this case setting the para_text to be displayed in top_para.

And that’s essentially it. Your projectcode directory could include whatever modules and packages you care to write, and your submit_data dictionary could call them to produce any sort of functionality.

Responding with JSON

After the Responder called your submit_data function, it passed the call on to the Template page 2001 which was returned to the remote browser, thus refreshing the page.

Skipole has another ability; certain widgets have the option of submitting data to a Responder which returns a JSON page – which essentially returns the data from the page_data dictionary and updates the page.

This has the advantage that the whole page is not refreshed, just the bits you want are updated. Looking like a cleaner and quicker response to the user. Lets try it. First we need another Responder, the easiest way is to copy Responder 2, and edit the new one. So go to the Root Folder page and on the top ‘Site root’ line choose ‘Add Page’.

Then set the radio button ‘Copy an existing page’, set a description of something like ‘accepts input, returns JSON’, set the ident number to be 3, and a page name of json_responce.

You will then see a page requesting the ident of the page to be copied, input 2 and press submit.

This will return you to the Root Folder where you should see a new Responder with ident of 3. Choose its Edit button, and you will see parameters that are the same as Responder 2 – which is reasonable since it is a copy of 2.

The only difference we are about to set, is rather than have a target page of the Template 2001, we are setting a JSON page as the target. We do not have to create a JSON page, since an empty one, used for this purpose already exists, and has label “general_json”.

So in the field “Ident or label of target page” set general_json and press submit.

So the Responder is done, however we now have to let the form widget know it can send its data to Responder 3. Return to Root Folder, and choose the Edit button of page 2001

Then from the left panel choose ‘index_template – Body’, and from widget ‘in_form’ choose ‘Edit’.

You will see a field ‘action_json’. Follow its link and set 3 into the field value and press Submit.

Choose the left panel Admin button and then ‘Commit Project’ to save your changes.

You will notice the ‘action’ field of the in_form widget is still set to 2. If the client browser has javascript disabled, then the form continues to call 2, and gets the Template page as a response, however if it has javascript enabled, it picks up the 3 – calls the Responder 3 and expects a JSON page in return, which is then used to update the page.

Try going to your project page again, refresh it so everything is up to date, and try submitting a name. It should work faster without any visible page refresh.

And Finally

From the skiadmin page download the project tar file, extract it onto a Pi and run


You can then connect over a network by calling the Pi ip address and port 8000, - if you want to run it on port 80, the normal http port, then you will have to run the server with:

sudo python3 -p 80

This may be a security concern if you are putting the Pi on the internet, in fact, depending on your own Python functions, you may well be introducing a severe security risk to your network. So unless you are sure of what you are doing, I suggest you initially use this on internal networks only.

Skipole has quite a bit of further functionality, each page has a ‘help’ button in the top right hand corner, which is worth viewing, and the wiki pages at its development site are useful.