""" django_extensions.management.jobs """ import os from imp import find_module _jobs = None def noneimplementation(meth): return None class JobError(Exception): pass class BaseJob(object): help = "undefined job description." when = None def execute(self): raise NotImplementedError("Job needs to implement the execute method") class HourlyJob(BaseJob): when = "hourly" class DailyJob(BaseJob): when = "daily" class WeeklyJob(BaseJob): when = "weekly" class MonthlyJob(BaseJob): when = "monthly" def my_import(name): imp = __import__(name) mods = name.split('.') if len(mods)>1: for mod in mods[1:]: imp = getattr(imp, mod) return imp def find_jobs(jobs_dir): try: return [f[:-3] for f in os.listdir(jobs_dir) \ if not f.startswith('_') and f.endswith(".py")] except OSError: return [] def find_job_module(app_name, when=None): parts = app_name.split('.') parts.append('jobs') if when: parts.append(when) parts.reverse() path = None while parts: part = parts.pop() f, path, descr = find_module(part, path and [path] or None) return path def import_job(app_name, name, when=None): jobmodule = "%s.jobs.%s%s" % (app_name, when and "%s." % when or "", name) job_mod = my_import(jobmodule) # todo: more friendly message for AttributeError if job_mod does not exist try: job = job_mod.Job except: raise JobError("Job module %s does not contain class instance named 'Job'" % jobmodule) if when and not (job.when == when or job.when == None): raise JobError("Job %s is not a %s job." % (jobmodule, when)) return job def get_jobs(when=None, only_scheduled=False): """ Returns a dictionary mapping of job names together with there respective application class. """ global _jobs # FIXME: HACK: make sure the project dir is on the path when executed as ./manage.py import sys try: cpath = os.path.dirname(os.path.realpath(sys.argv[0])) ppath = os.path.dirname(cpath) if ppath not in sys.path: sys.path.append(ppath) except: pass if _jobs is None: _jobs = {} if True: from django.conf import settings for app_name in settings.INSTALLED_APPS: scandirs = (None, 'hourly', 'daily', 'weekly', 'monthly') if when: scandirs = None, when for subdir in scandirs: try: path = find_job_module(app_name, subdir) for name in find_jobs(path): if (app_name, name) in _jobs: raise JobError("Duplicate job %s" % name) job = import_job(app_name, name, subdir) if only_scheduled and job.when == None: # only include jobs which are scheduled continue if when and job.when != when: # generic job not in same schedule continue _jobs[(app_name, name)] = job except ImportError: pass # No job module -- continue scanning return _jobs def get_job(app_name, job_name): jobs = get_jobs() if app_name: return jobs[(app_name, job_name)] else: for a, j in jobs.keys(): if j==job_name: return jobs[(a, j)] raise KeyError("Job not found: %s" % job_name) def print_jobs(when=None, only_scheduled=False, show_when=True, \ show_appname=False, show_header=True): jobmap = get_jobs(when, only_scheduled=only_scheduled) print "Job List: %i jobs" % len(jobmap) jlist = jobmap.keys() jlist.sort() appname_spacer = "%%-%is" % max(len(e[0]) for e in jlist) name_spacer = "%%-%is" % max(len(e[1]) for e in jlist) when_spacer = "%%-%is" % max(len(e.when) for e in jobmap.values() if e.when) if show_header: line = " " if show_appname: line += appname_spacer % "appname" + " - " line += name_spacer % "jobname" if show_when: line += " - " + when_spacer % "when" line += " - help" print line print "-"*80 for app_name, job_name in jlist: job = jobmap[(app_name, job_name)] line = " " if show_appname: line += appname_spacer % app_name + " - " line += name_spacer % job_name if show_when: line += " - " + when_spacer % (job.when and job.when or "") line += " - " + job.help print line