Fetchez le Python

Technical blog on the Python programming language, in a pure Frenglish style. Main topics are Python and Mozilla – This blog does not engage my employer

Category: windows

Buildout: plone.org and pypi.python.org are acting like SPOF

Yesterday, plone.org was moved on another server. It was an horrible day for our people here that didn’t have a local cache of eggs to build their instances. So plone.org was acting like a Single Point Of Failure(SPOF) for some packages.

A few developers, that are under windows, were even having permission denied errors on their buildout because when a package is badly downloaded is not correctly crushed before a new attempt (I need to add a ticket about this in setuptools tracker I guess).

Anyway, we decided to create a mirror here, (I am buiding it at http://release.ingeniweb.com/ this morning hopefully) to avoid such problems.

This makes me think that zc.buildout should introduce a high-level mirror mechanism in the find-links variable, that would let someone explicitely provide a list of mirror. It could look like this:

find-links =
  http://pypi.python.org/simple |  http://release.ingeniweb.com/pypi-mirror
  http://dist.plone.org |  http://release.ingeniweb.com/plone-dist-mirror

It could be used to switch the find-links values sent to setuptools when the primary url is down by attempting a simple call with a timeout.

Advertisements

An installer for a buildout-ready Windows

When you need to run a buildout under Windows, you have to take care of setting up quite a few things, like installing MinGW and linking it to Python, and setting up a svn command-line client for most buildouts.

We created a simple package that contains everything needed to make your windows buildout-friendly. It is a simple zip file that contains a batch script and third-party installers. When the batch is run, the environment variables are set as well, and win32-compatible buildouts should run without problems from there.

EDIT: the downloads urls have changed (thanks Sasha!)

You can get it here:

http://dl.dropbox.com/u/3265240/python2.4.4-win32.zip

and another version that adds developing tools like vim and tail:

http://dl.dropbox.com/u/3265240/python2.4.4-win32-dev.zip

This zip file is built itself with a buildout that we might publish soon so you can make a custom zip file.

Scheduling tasks in Windows with PyWin32

I am posting this small entry because it took me quite a time to compute all informations to programmatically add tasks in Windows using pywin32, so this post should be an helpfull example.

The process to schedule a task is as follows:

  • create an instance of the COM TaskScheduler interface
  • adding a task within the task scheduler
  • adding a trigger within the task

Here’s how it can look in Python, to create daily tasks:

import pythoncom, win32api
import time
from win32com.taskscheduler import taskscheduler

def create_daily_task(name, cmd, hour=None, minute=None):
    """creates a daily task"""
    cmd = cmd.split()
    ts = pythoncom.CoCreateInstance(taskscheduler.CLSID_CTaskScheduler,None,
                                    pythoncom.CLSCTX_INPROC_SERVER,
                                    taskscheduler.IID_ITaskScheduler)

    if '%s.job' % name not in ts.Enum():
        task = ts.NewWorkItem(name)

        task.SetApplicationName(cmd[0])
        task.SetParameters(' '.join(cmd[1:]))
        task.SetPriority(taskscheduler.REALTIME_PRIORITY_CLASS)
        task.SetFlags(taskscheduler.TASK_FLAG_RUN_ONLY_IF_LOGGED_ON)
        task.SetAccountInformation('', None)
        ts.AddWorkItem(name, task)
        run_time = time.localtime(time.time() + 300)
        tr_ind, tr = task.CreateTrigger()
        tt = tr.GetTrigger()
        tt.Flags = 0
        tt.BeginYear = int(time.strftime('%Y', run_time))
        tt.BeginMonth = int(time.strftime('%m', run_time))
        tt.BeginDay = int(time.strftime('%d', run_time))
        if minute is None:
            tt.StartMinute = int(time.strftime('%M', run_time))
        else:
            tt.StartMinute = minute
        if hour is None:
            tt.StartHour = int(time.strftime('%H', run_time))
        else:
            tt.StartHour = hour
        tt.TriggerType = int(taskscheduler.TASK_TIME_TRIGGER_DAILY)
        tr.SetTrigger(tt)
        pf = task.QueryInterface(pythoncom.IID_IPersistFile)
        pf.Save(None,1)
        task.Run()
    else:
        raise KeyError("%s already exists" % name)

    task = ts.Activate(name)
    exit_code, startup_error_code = task.GetExitCode()
    return win32api.FormatMessage(startup_error_code)

You can see an example of usage here, in the iw.win32 package we have started to build, to gather all win32 specific Python things.