3 # Copyright 2007 Google Inc.
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
9 # http://www.apache.org/licenses/LICENSE-2.0
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
20 A library for working with CronInfo records, describing cron entries for an
21 application. Supports loading the records from yaml.
35 from google
.appengine
.cron
import groc
36 from google
.appengine
.api
import validation
37 from google
.appengine
.api
import yaml_builder
38 from google
.appengine
.api
import yaml_listener
39 from google
.appengine
.api
import yaml_object
42 _TIMEZONE_REGEX
= r
'^.{0,100}$'
43 _DESCRIPTION_REGEX
= r
'^.{0,499}$'
46 class GrocValidator(validation
.Validator
):
47 """Checks that a schedule is in valid groc format."""
49 def Validate(self
, value
):
50 """Validates a schedule."""
52 raise validation
.MissingAttribute('schedule must be specified')
53 if not isinstance(value
, basestring
):
54 raise TypeError('schedule must be a string, not \'%r\''%type(value
))
55 schedule
= groc
.CreateParser(value
)
58 except groc
.GrocException
, e
:
59 raise validation
.ValidationError('schedule \'%s\' failed to parse: %s'%(
64 class TimezoneValidator(validation
.Validator
):
65 """Checks that a timezone can be correctly parsed and is known."""
67 def Validate(self
, value
):
68 """Validates a timezone."""
71 if not isinstance(value
, basestring
):
72 raise TypeError('timezone must be a string, not \'%r\'' % type(value
))
77 except pytz
.UnknownTimeZoneError
:
78 raise validation
.ValidationError('timezone \'%s\' is unknown' % value
)
82 unused_e
, v
, t
= sys
.exc_info()
83 logging
.warning('pytz raised an unexpected error: %s.\n' % (v
) +
84 'Traceback:\n' + '\n'.join(traceback
.format_tb(t
)))
94 DESCRIPTION
= 'description'
97 class MalformedCronfigurationFile(Exception):
98 """Configuration file for Cron is malformed."""
102 class CronEntry(validation
.Validated
):
103 """A cron entry describes a single cron job."""
106 SCHEDULE
: GrocValidator(),
107 TIMEZONE
: TimezoneValidator(),
108 DESCRIPTION
: validation
.Optional(_DESCRIPTION_REGEX
)
112 class CronInfoExternal(validation
.Validated
):
113 """CronInfoExternal describes all cron entries for an application."""
115 CRON
: validation
.Optional(validation
.Repeated(CronEntry
))
119 def LoadSingleCron(cron_info
):
120 """Load a cron.yaml file or string and return a CronInfoExternal object."""
121 builder
= yaml_object
.ObjectBuilder(CronInfoExternal
)
122 handler
= yaml_builder
.BuilderHandler(builder
)
123 listener
= yaml_listener
.EventListener(handler
)
124 listener
.Parse(cron_info
)
126 cron_info
= handler
.GetResults()
127 if len(cron_info
) < 1:
128 raise MalformedCronfigurationFile('Empty cron configuration.')
129 if len(cron_info
) > 1:
130 raise MalformedCronfigurationFile('Multiple cron sections '