| 1 | = Python scripting framework = |
| 2 | |
| 3 | See the section on Python in the [http://boinc.berkeley.edu/trac/wiki/SoftwarePrereqsUnix Software Prerequisites]. |
| 4 | == Structure == |
| 5 | 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. |
| 6 | == Project-specific settings == |
| 7 | 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 |
| 8 | 1. modify this file directly (if you have only one project on your server or have separate copies for each) |
| 9 | 1. create a new boinc_project_path.py and place it earlier in PYTHONPATH than the default one |
| 10 | 1. define environment variables |
| 11 | |
| 12 | Example `boinc_project_path.py` |
| 13 | {{{ |
| 14 | config_xml_filename = '/etc/boinc/yetiathome/config.xml' |
| 15 | run_state_xml_filename = '/var/lib/boinc/yetiathome/run_state.xml' |
| 16 | }}} |
| 17 | See the source of file `boinc/py/Boinc/boinc_project_path.py` for details. |
| 18 | == Directories containing python scripts == |
| 19 | |
| 20 | |
| 21 | |
| 22 | |
| 23 | |
| 24 | == Python modules in '''boinc/py/Boinc/''' == |
| 25 | |
| 26 | |
| 27 | |
| 28 | |
| 29 | |
| 30 | == Python database access == |
| 31 | `Database.py` defines database backend library and database table and object relationships to allow easy data manipulation. All [DataBase 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: |
| 32 | |
| 33 | |
| 34 | {{{ |
| 35 | from Boinc import database |
| 36 | }}} |
| 37 | Connect to the database: |
| 38 | {{{ |
| 39 | database.connect_default_config() |
| 40 | }}} |
| 41 | Table classes can be indexed using the [ ] operator to retrieve an object by id; e.g. |
| 42 | {{{ |
| 43 | # executes 'select * from project where id=1'. |
| 44 | # exception is raised if project is not found |
| 45 | project_with_id_1 = database.Projects[1] |
| 46 | }}} |
| 47 | Table classes have a `find` function that builds and executes a MySQL query based on its arguments: |
| 48 | {{{ |
| 49 | # this could return any number (0, 1, 2, ...) of platforms |
| 50 | # executes "select * from platform where user_friendly_name='commodore 64'" |
| 51 | list_of_platforms_called_c64 = database.Platforms.find( |
| 52 | user_friendly_name = 'Commodore 64') |
| 53 | }}} |
| 54 | 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. |
| 55 | {{{ |
| 56 | all_apps = database.Apps.find() |
| 57 | finished_yeti_wus = database.Workunits.find( |
| 58 | app = database.Apps.find(name='YETI@home')[0], |
| 59 | assimilate_state = ASSIMILATE_DONE) |
| 60 | }}} |
| 61 | Objects (table rows) have their column data as members so you can access and modify them directly. |
| 62 | {{{ |
| 63 | user_quarl = database.users.find(email_addr='quarl@quarl.org')[0] |
| 64 | print 'name =', user_quarl.name |
| 65 | user_quarl.postal_code = 97404 |
| 66 | }}} |
| 67 | To create a new database object, create a Python object and give all values as parameters to the initializer: |
| 68 | {{{ |
| 69 | new_app = database.App(name='SPAGHETTI@home', |
| 70 | min_version=1, |
| 71 | create_time=time.time()) |
| 72 | }}} |
| 73 | To commit any changes (including a new object), call `commit()` (the tool `boinc/tools/add.py` is a command-line interface to this): |
| 74 | {{{ |
| 75 | user_quarl.commit() # executes an UPDATE |
| 76 | new_app.commit() # executes an INSERT |
| 77 | }}} |
| 78 | To remove an object, call `remove()`: |
| 79 | {{{ |
| 80 | team_eric_test = database.Teams(name="Eric's Test Team")[0] |
| 81 | team_eric_test.remove() |
| 82 | # OR |
| 83 | for team in database.Teams(name="Eric's Test Team"): |
| 84 | team.remove() |
| 85 | # OR |
| 86 | map(database.Team.remove,database.Teams(name="Eric's Test Team")) |
| 87 | }}} |
| 88 | 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`) |
| 89 | {{{ |
| 90 | wu_1234 = database.Workunits.find(name='1234.wu')[0] |
| 91 | results_of_wu_1234 = database.Results.find(workunit=wu_1234) |
| 92 | for result in results_of_wu_1234: |
| 93 | os.system("echo 'you are crunching %s' | mail '%s'" %( |
| 94 | result.name, result.host.user.email_addr)) |
| 95 | }}} |