wiki:PythonFramework

Version 7 (modified by Nicolas, 17 years ago) (diff)

Replace template

Python scripting framework

T(Incomplete)?

See the section on Python in the Software Prerequisites.

Structure

The directory boinc/py/Boinc contains the Boinc module. This means if you have boinc/py/ in your python path you can write for example:

from Boinc.setup_project import *

To ensure boinc/py/ is in your python path:

import boinc_path_config

This is a special module that configure places in relevant directories which then modifies sys.path appropriately.

Project-specific settings

The module boinc_project_path is imported to get the paths for config.xml and run_state.xml. The default paths for these are the parent directory of the invocation script. You can override these defaults

  1. modify this file directly (if you have only one project on your server or have separate copies for each)
  2. create a new boinc_project_path.py and place it earlier in PYTHONPATH than the default one
  3. define environment variables

Example boinc_project_path.py

  config_xml_filename = '/etc/boinc/yetiathome/config.xml'
  run_state_xml_filename = '/var/lib/boinc/yetiathome/run_state.xml'

See the source of file boinc/py/Boinc/boinc_project_path.py for details.

Directories containing python scripts

boinc/py/Boinc/*.pyMain BOINC python modules
boinc/sched/startBOINC start / Super Cron program
boinc/tools/xaddAdds objects to the database
boinc/tools/make_projectCreates a project
boinc/tools/update_versionsAdds all relevant core client and application executables to download directory and database
boinc/test/test*.py
cgiserver.py
Test scripts: see the testing framework.

Python modules in boinc/py/Boinc/

boinc_path_config.py.inConfigure puts boinc_path_config.py in all directories that need it; see above
boinc_project_path.pysets where config.xml et al can be found; see above.
configxml.pyreads and writes config.xml and run_state.xml - see its pydoc for more information
boinc_db.pyauto-generated file that contains database constant definitions, e.g. RESULT_OUTCOME_SUCCESS = 1
setup_project.pyinternal module for creating a project. See make_project and test scripts.
database.pydefines database backend functions and database operations; see below.
db_mid.py'middle-end': optional mix-in to ease debugging by allowing printing of database objects directly
util.pymiscellaneous functions
version.py.inversion and platform-specific definitions snarfed by configure

Python database access

Database.py defines database backend library and database table and object relationships to allow easy data manipulation.

All database tables have a corresponding class and its rows have classes, where each column is a member of that class. Ids are automatically translated to and from objects. To begin, import the database module:

from Boinc import database

Connect to the database:

database.connect_default_config()

Table classes can be indexed using the [ ] operator to retrieve an object by id; e.g.

# executes 'select * from project where id=1'.
# exception is raised if project is not found
project_with_id_1 = database.Projects[1]

Table classes have a find function that builds and executes a MySQL query based on its arguments:

# this could return any number (0, 1, 2, ...) of platforms
# executes "select * from platform where user_friendly_name='commodore 64'"
list_of_platforms_called_c64 = database.Platforms.find(
    user_friendly_name = 'Commodore 64')

Find can take any number of arguments; they are ANDed. For more advanced usage such as custom SQL queries (anything is possible) see the pydoc.

all_apps = database.Apps.find()
finished_yeti_wus = database.Workunits.find(
    app = database.Apps.find(name='YETI@home')[0],
    assimilate_state = ASSIMILATE_DONE)

Objects (table rows) have their column data as members so you can access and modify them directly.

user_quarl = database.users.find(email_addr='quarl@quarl.org')[0]
print 'name =', user_quarl.name
user_quarl.postal_code = 97404

To create a new database object, create a Python object and give all values as parameters to the initializer:

new_app = database.App(name='SPAGHETTI@home',
                       min_version=1,
                       create_time=time.time())

To commit any changes (including a new object), call commit() (the tool boinc/tools/add.py is a command-line interface to this):

user_quarl.commit()  # executes an UPDATE
new_app.commit()     # executes an INSERT

To remove an object, call remove():

team_eric_test = database.Teams(name="Eric's Test Team")[0]
team_eric_test.remove()
#                        OR
for team in database.Teams(name="Eric's Test Team"):
    team.remove()
#                        OR
map(database.Team.remove,database.Teams(name="Eric's Test Team"))

To access objects related by id, access the field name without "id" suffix: (the result table has columns 'workunitid' and 'hostid'; the host table has column userid)

wu_1234 = database.Workunits.find(name='1234.wu')[0]
results_of_wu_1234 = database.Results.find(workunit=wu_1234)
for result in results_of_wu_1234:
    os.system("echo 'you are crunching %s' | mail '%s'" %(
               result.name, result.host.user.email_addr))
TablePython table objectPython row object class
projectProjectsProject
platformPlatformsPlatform
appAppsApp
app_versionAppVersionsAppVersion
userUsersUser
teamTeamsTeam
hostHostsHost
workunitWorkunitsWorkunit
resultResultsResult