• Home
  • History
  • Annotate
Name Date Size #Lines LOC

..03-May-2022-

tests/H03-May-2022-2,6801,929

.gitignoreH A D23-Oct-2019120 1514

.pylintrcH A D23-Oct-20196.8 KiB237156

AUTHORSH A D23-Oct-201934 21

COPYINGH A D23-Oct-20197.5 KiB166128

MANIFEST.inH A D23-Oct-2019265 1312

README.rstH A D23-Oct-201912.8 KiB414271

coverage.shH A D23-Oct-2019285 74

cronlog.pyH A D23-Oct-20193.8 KiB12484

crontab.pyH A D23-Oct-201943.9 KiB1,3621,090

crontabs.pyH A D23-Oct-20194.3 KiB146102

setup.pyH A D23-Oct-20192.7 KiB8254

README.rst

1Python Crontab
2--------------
3
4.. image:: https://gitlab.com/doctormo/python-crontab/raw/master/branding.svg
5
6.. image:: https://badge.fury.io/py/python-crontab.svg
7    :target: https://badge.fury.io/py/python-crontab
8.. image:: https://img.shields.io/badge/License-LGPL%20v3-blue.svg
9    :target: https://gitlab.com/doctormo/python-crontab/raw/master/COPYING
10
11Bug Reports and Development
12===========================
13
14Please report any problems to the `GitLab issues tracker <https://gitlab.com/doctormo/python-crontab/issues>`_. Please use Git and push patches to the `GitLab project code hosting <https://gitlab.com/doctormo/python-crontab>`_.
15
16**Note:** If you get the error ``TypeError: __init__() takes exactly 2 arguments`` when using CronTab, you have the wrong module installed. You need to install ``python-crontab`` and not ``crontab`` from pypi or your local package manager and try again.
17
18Description
19===========
20
21Crontab module for reading and writing crontab files and accessing the system cron
22automatically and simply using a direct API.
23
24Comparing the `below chart <http://en.wikipedia.org/wiki/Cron#CRON_expression>`_
25you will note that W, L, # and ? symbols are not supported as they are not
26standard Linux or SystemV crontab format.
27
28+-------------+-----------+-----------------+-------------------+-------------+
29|Field Name   |Mandatory  |Allowed Values   |Special Characters |Extra Values |
30+=============+===========+=================+===================+=============+
31|Minutes      |Yes        |0-59             |\* / , -           | < >         |
32+-------------+-----------+-----------------+-------------------+-------------+
33|Hours        |Yes        |0-23             |\* / , -           | < >         |
34+-------------+-----------+-----------------+-------------------+-------------+
35|Day of month |Yes        |1-31             |\* / , -           | < >         |
36+-------------+-----------+-----------------+-------------------+-------------+
37|Month        |Yes        |1-12 or JAN-DEC  |\* / , -           | < >         |
38+-------------+-----------+-----------------+-------------------+-------------+
39|Day of week  |Yes        |0-6 or SUN-SAT   |\* / , -           | < >         |
40+-------------+-----------+-----------------+-------------------+-------------+
41
42Extra Values are '<' for minimum value, such as 0 for minutes or 1 for months.
43And '>' for maximum value, such as 23 for hours or 12 for months.
44
45Supported special cases allow crontab lines to not use fields.
46These are the supported aliases which are not available in SystemV mode:
47
48=========== ============
49Case        Meaning
50=========== ============
51@reboot     Every boot
52@hourly     0 * * * *
53@daily      0 0 * * *
54@weekly     0 0 * * 0
55@monthly    0 0 1 * *
56@yearly     0 0 1 1 *
57@annually   0 0 1 1 *
58@midnight   0 0 * * *
59=========== ============
60
61How to Use the Module
62=====================
63
64**Note:** Several users have reported their new crontabs not saving automatically or that the module doesn't do anything. You **MUST** use write() if you want your edits to be saved out. See below for full details on the use of the write function.
65
66Getting access to a crontab can happen in five ways, three system methods that
67will work only on Unix and require you to have the right permissions::
68
69    from crontab import CronTab
70
71    empty_cron    = CronTab()
72    my_user_cron  = CronTab(user=True)
73    users_cron    = CronTab(user='username')
74
75And two ways from non-system sources that will work on Windows too::
76
77    file_cron = CronTab(tabfile='filename.tab')
78    mem_cron = CronTab(tab="""
79      * * * * * command
80    """)
81
82Special per-command user flag for vixie cron format (new in 1.9)::
83
84    system_cron = CronTab(tabfile='/etc/crontab', user=False)
85    job = system_cron[0]
86    job.user != None
87    system_cron.new(command='new_command', user='root')
88
89Creating a new job is as simple as::
90
91    job  = cron.new(command='/usr/bin/echo')
92
93And setting the job's time restrictions::
94
95    job.minute.during(5,50).every(5)
96    job.hour.every(4)
97    job.day.on(4, 5, 6)
98
99    job.dow.on('SUN')
100    job.dow.on('SUN', 'FRI')
101    job.month.during('APR', 'NOV')
102
103Each time restriction will clear the previous restriction::
104
105    job.hour.every(10) # Set to * */10 * * *
106    job.hour.on(2)     # Set to * 2 * * *
107
108Appending restrictions is explicit::
109
110    job.hour.every(10)  # Set to * */10 * * *
111    job.hour.also.on(2) # Set to * 2,*/10 * * *
112
113Setting all time slices at once::
114
115    job.setall(2, 10, '2-4', '*/2', None)
116    job.setall('2 10 * * *')
117
118Setting the slice to a python date object::
119
120    job.setall(time(10, 2))
121    job.setall(date(2000, 4, 2))
122    job.setall(datetime(2000, 4, 2, 10, 2))
123
124Run a jobs command. Running the job here will not effect it's
125existing schedule with another crontab process::
126
127    job_standard_output = job.run()
128
129Creating a job with a comment::
130
131    job = cron.new(command='/foo/bar', comment='SomeID')
132
133Get the comment or command for a job::
134
135    command = job.command
136    comment = job.comment
137
138Modify the comment or command on a job::
139
140    job.set_command("new_script.sh")
141    job.set_comment("New ID or comment here")
142
143Disabled or Enable Job::
144
145    job.enable()
146    job.enable(False)
147    False is job.is_enabled()
148
149Validity Check::
150
151    True is job.is_valid()
152
153Use a special syntax::
154
155    job.every_reboot()
156
157Find an existing job by command sub-match or regular expression::
158
159    iter = cron.find_command('bar') # matches foobar1
160    iter = cron.find_command(re.compile(r'b[ab]r$'))
161
162Find an existing job by comment exact match or regular expression::
163
164    iter = cron.find_comment('ID or some text')
165    iter = cron.find_comment(re.compile(' or \w'))
166
167Find an existing job by schedule::
168
169    iter = cron.find_time(2, 10, '2-4', '*/2', None)
170    iter = cron.find_time("*/2 * * * *")
171
172Clean a job of all rules::
173
174    job.clear()
175
176Iterate through all jobs, this includes disabled (commented out) cron jobs::
177
178    for job in cron:
179        print(job)
180
181Iterate through all lines, this includes all comments and empty lines::
182
183    for line in cron.lines:
184        print(line)
185
186Remove Items::
187
188    cron.remove( job )
189    cron.remove_all('echo')
190    cron.remove_all(comment='foo')
191    cron.remove_all(time='*/2')
192
193Clear entire cron of all jobs::
194
195    cron.remove_all()
196
197Write CronTab back to system or filename::
198
199    cron.write()
200
201Write CronTab to new filename::
202
203    cron.write( 'output.tab' )
204
205Write to this user's crontab (unix only)::
206
207    cron.write_to_user( user=True )
208
209Write to some other user's crontab::
210
211    cron.write_to_user( user='bob' )
212
213Validate a cron time string::
214
215    from crontab import CronSlices
216    bool = CronSlices.is_valid('0/2 * * * *')
217
218Compare list of cron objects against another and return the difference::
219
220    difference = set([CronItem1, CronItem2, CronItem3]) - set([CronItem2, CronItem3])
221
222Compare two CronItems for equality::
223
224    CronItem1 = CronTab(tab="* * * * * COMMAND # Example Job")
225    CronItem2 = CronTab(tab="10 * * * * COMMAND # Example Job 2")
226    if CronItem1 != CronItem2:
227        print("Cronjobs do not match")
228
229Environment Variables
230=====================
231
232Some versions of vixie cron support variables outside of the command line.
233Sometimes just update the envronment when commands are run, the Cronie fork
234of vixie cron also supports CRON_TZ which looks like a regular variable but
235actually changes the times the jobs are run at.
236
237Very old vixie crons don't support per-job variables, but most do.
238
239Iterate through cron level environment variables::
240
241    for (name, value) in cron.env.items():
242        print(name)
243        print(value)
244
245Create new or update cron level environment variables::
246
247    print(cron.env['SHELL'])
248    cron.env['SHELL'] = '/bin/bash'
249    print(cron.env)
250
251Each job can also have a list of environment variables::
252
253    for job in cron:
254        job.env['NEW_VAR'] = 'A'
255        print(job.env)
256
257
258Proceeding Unit Confusion
259=========================
260
261It is sometimes logical to think that job.hour.every(2) will set all proceeding
262units to '0' and thus result in "0 \*/2 * * \*". Instead you are controlling
263only the hours units and the minute column is unaffected. The real result would
264be "\* \*/2 * * \*" and maybe unexpected to those unfamiliar with crontabs.
265
266There is a special 'every' method on a job to clear the job's existing schedule
267and replace it with a simple single unit::
268
269    job.every(4).hours()  == '0 */4 * * *'
270    job.every().dom()     == '0 0 * * *'
271    job.every().month()   == '0 0 0 * *'
272    job.every(2).dows()   == '0 0 * * */2'
273
274This is a convenience method only, it does normal things with the existing api.
275
276Running the Scheduler
277=====================
278
279The module is able to run a cron tab as a daemon as long as the optional
280croniter module is installed; each process will block and errors will
281be logged (new in 2.0).
282
283(note this functionality is new and not perfect, if you find bugs report them!)
284
285Running the scheduler::
286
287    tab = CronTab(tabfile='MyScripts.tab')
288    for result in tab.run_scheduler():
289        print("This was printed to stdout by the process.")
290
291Do not do this, it won't work because it returns generator function::
292
293    tab.run_scheduler()
294
295Timeout and cadence can be changed for testing or error management::
296
297    for result in tab.run_scheduler(timeout=600):
298        print("Will run jobs every 1 minutes for ten minutes from now()")
299
300    for result in tab.run_scheduler(cadence=1, warp=True):
301        print("Will run jobs every 1 second, counting each second as 1 minute")
302
303Frequency Calculation
304=====================
305
306Every job's schedule has a frequency. We can attempt to calculate the number
307of times a job would execute in a give amount of time. We have three simple
308methods::
309
310    job.setall("1,2 1,2 * * *")
311    job.frequency_per_day() == 4
312
313The per year frequency method will tell you how many days a year the
314job would execute::
315
316    job.setall("* * 1,2 1,2 *")
317    job.frequency_per_year(year=2010) == 4
318
319These are combined to give the number of times a job will execute in any year::
320
321    job.setall("1,2 1,2 1,2 1,2 *")
322    job.frequency(year=2010) == 16
323
324Frequency can be quickly checked using python built-in operators::
325
326    job < "*/2 * * * *"
327    job > job2
328    job.slices == "*/5"
329
330Log Functionality
331=================
332
333The log functionality will read a cron log backwards to find you the last run
334instances of your crontab and cron jobs.
335
336The crontab will limit the returned entries to the user the crontab is for::
337
338    cron = CronTab(user='root')
339
340    for d in cron.log:
341        print(d['pid'] + " - " + d['date'])
342
343Each job can return a log iterator too, these are filtered so you can see when
344the last execution was::
345
346    for d in cron.find_command('echo')[0].log:
347        print(d['pid'] + " - " + d['date'])
348
349All System CronTabs Functionality
350=================================
351
352The crontabs (note the plural) module can attempt to find all crontabs on the
353system. This works well for Linux systems with known locations for cron files
354and user spolls. It will even extract anacron jobs so you can get a picture
355of all the jobs running on your system::
356
357    from crontabs import CronTabs
358
359    for cron in CronTabs():
360        print(repr(cron))
361
362All jobs can be brought together to run various searches, all jobs are added
363to a CronTab object which can be used as documented above::
364
365   jobs = CronTabs().all.find_command('foo')
366
367Schedule Functionality
368======================
369
370If you have the croniter python module installed, you will have access to a
371schedule on each job. For example if you want to know when a job will next run::
372
373    schedule = job.schedule(date_from=datetime.now())
374
375This creates a schedule croniter based on the job from the time specified. The
376default date_from is the current date/time if not specified. Next we can get
377the datetime of the next job::
378
379    datetime = schedule.get_next()
380
381Or the previous::
382
383    datetime = schedule.get_prev()
384
385The get methods work in the same way as the default croniter, except that they
386will return datetime objects by default instead of floats. If you want the
387original functionality, pass float into the method when calling::
388
389    datetime = schedule.get_current(float)
390
391If you don't have the croniter module installed, you'll get an ImportError when
392you first try using the schedule function on your cron job object.
393
394Descriptor Functionality
395========================
396
397If you have the cron-descriptor module installed, you will be able to ask for a
398translated string which describes the frequency of the job in the current
399locale language. This should be mostly human readable.
400
401
402    print(job.description(use_24hour_time_format=True))
403
404See cron-descriptor for details of the supported languages and options.
405
406Extra Support
407=============
408
409 - Support for vixie cron with username addition with user flag
410 - Support for SunOS, AIX & HP with compatibility 'SystemV' mode.
411 - Python 3 (3.5, 3.6, 3.7) and Python 2.7 tested, python 2.6 removed from support.
412 - Windows support works for non-system crontabs only.
413   ( see mem_cron and file_cron examples above for usage )
414