class AliasOptioned(validation.Validated): ATTRIBUTES = { 'color': validation.Options(('red', ['r', 'RED']), ('green', ('g', 'GREEN')), ('blue', ['b', 'BLUE'])) }
class FetcherPolicyInfo(validation.Validated): """Configuration parameters for the fetcher_policy part of the job.""" ATTRIBUTES = { "agent_name": r".+", "email_address": r".+", "web_address": r".+", "min_response_rate": "[0-9]+", "max_content_size": validation.Optional(validation.Repeated(MaxContentSizeInfo)), "crawl_end_time": "[0-9]+", "crawl_delay": "[0-9]+", "max_redirects": "[0-9]+", "accept_language": r".+", "valid_mime_types": r".+", "redirect_mode": validation.Options(FOLLOW_ALL, FOLLOW_NONE, default=FOLLOW_ALL), "request_timeout": r".+", }
class AppInfoExternal(validation.Validated): """Class representing users application info. This class is passed to a yaml_object builder to provide the validation for the application information file format parser. Attributes: application: Unique identifier for application. version: Application's major version number. runtime: Runtime used by application. api_version: Which version of APIs to use. handlers: List of URL handlers. default_expiration: Default time delta to use for cache expiration for all static files, unless they have their own specific 'expiration' set. See the URLMap.expiration field's documentation for more information. skip_files: An re object. Files that match this regular expression will not be uploaded by appcfg.py. For example: skip_files: | .svn.*| #.*# """ ATTRIBUTES = { APPLICATION: APPLICATION_RE_STRING, VERSION: VERSION_RE_STRING, RUNTIME: validation.Options(RUNTIME_PYTHON), API_VERSION: validation.Options('1', 'beta'), HANDLERS: validation.Optional(validation.Repeated(URLMap)), DEFAULT_EXPIRATION: validation.Optional(_EXPIRATION_REGEX), SKIP_FILES: validation.RegexStr(default=DEFAULT_SKIP_FILES) } def CheckInitialized(self): """Ensures that at least one url mapping is provided. Raises: MissingURLMapping when no URLMap objects are present in object. TooManyURLMappings when there are too many URLMap entries. """ super(AppInfoExternal, self).CheckInitialized() if not self.handlers: raise appinfo_errors.MissingURLMapping( 'No URLMap entries found in application configuration') if len(self.handlers) > MAX_URL_MAPS: raise appinfo_errors.TooManyURLMappings( 'Found more than %d URLMap entries in application configuration' % MAX_URL_MAPS)
class HandlerBase(validation.Validated): """Base class for URLMap and ApiConfigHandler.""" ATTRIBUTES = { URL: validation.Optional(_URL_REGEX), LOGIN: validation.Options(LOGIN_OPTIONAL, LOGIN_REQUIRED, LOGIN_ADMIN, default=LOGIN_OPTIONAL), AUTH_FAIL_ACTION: validation.Options(AUTH_FAIL_ACTION_REDIRECT, AUTH_FAIL_ACTION_UNAUTHORIZED, default=AUTH_FAIL_ACTION_REDIRECT), SECURE: validation.Options(SECURE_HTTP, SECURE_HTTPS, SECURE_HTTP_OR_HTTPS, SECURE_DEFAULT, default=SECURE_DEFAULT), HANDLER_SCRIPT: validation.Optional(_FILES_REGEX) }
class Property(validation.Validated): """Representation for an individual property of an index. Attributes: name: Name of attribute to sort by. direction: Direction of sort. """ ATTRIBUTES = { 'name': validation.TYPE_STR, 'direction': validation.Options(('asc', ('ascending',)), ('desc', ('descending',)), default='asc'), }
class Property(validation.Validated): """Representation for an individual property of an index. This class must be kept in sync with java/com/google/apphosting/utils/config/IndexYamlReader.java. Attributes: name: Name of attribute to sort by. direction: Direction of sort. """ ATTRIBUTES = { 'name': validation.Type(str, convert=False), 'direction': validation.Options(('asc', ('ascending', )), ('desc', ('descending', )), default='asc'), }
class Property(validation.Validated): """Representation for an individual property of an index. This class must be kept in sync with java/com/google/apphosting/utils/config/IndexYamlReader.java. Attributes: name: Name of attribute to sort by. direction: Direction of sort. mode: How the property is indexed. Either 'geospatial', 'segment' or None (unspecified). """ ATTRIBUTES = { 'name': validation.Type(str, convert=False), 'direction': validation.Options(('asc', ('ascending', )), ('desc', ('descending', )), default='asc'), 'mode': validation.Optional(['geospatial', 'segment']), } def __init__(self, **attributes): object.__setattr__(self, '_is_set', set([])) super(Property, self).__init__(**attributes) def __setattr__(self, key, value): self._is_set.add(key) super(Property, self).__setattr__(key, value) def IsAscending(self): return self.direction != 'desc' def CheckInitialized(self): if ('direction' in self._is_set and self.mode in ['geospatial', 'segment']): raise validation.ValidationError('Direction on a %s-mode ' 'property is not allowed.' % self.mode)
class URLMap(validation.Validated): """Mapping from URLs to handlers. This class acts like something of a union type. Its purpose is to describe a mapping between a set of URLs and their handlers. What handler type a given instance has is determined by which handler-id attribute is used. Each mapping can have one and only one handler type. Attempting to use more than one handler-id attribute will cause an UnknownHandlerType to be raised during validation. Failure to provide any handler-id attributes will cause MissingHandlerType to be raised during validation. The regular expression used by the url field will be used to match against the entire URL path and query string of the request. This means that partial maps will not be matched. Specifying a url, say /admin, is the same as matching against the regular expression '^/admin$'. Don't begin your matching url with ^ or end them with $. These regular expressions won't be accepted and will raise ValueError. Attributes: login: Whether or not login is required to access URL. Defaults to 'optional'. secure: Restriction on the protocol which can be used to serve this URL/handler (HTTP, HTTPS or either). url: Regular expression used to fully match against the request URLs path. See Special Cases for using static_dir. static_files: Handler id attribute that maps URL to the appropriate file. Can use back regex references to the string matched to url. upload: Regular expression used by the application configuration program to know which files are uploaded as blobs. It's very difficult to determine this using just the url and static_files so this attribute must be included. Required when defining a static_files mapping. A matching file name must fully match against the upload regex, similar to how url is matched against the request path. Do not begin upload with ^ or end it with $. static_dir: Handler id that maps the provided url to a sub-directory within the application directory. See Special Cases. mime_type: When used with static_files and static_dir the mime-type of files served from those directories are overridden with this value. script: Handler id that maps URLs to scipt handler within the application directory that will run using CGI. position: Used in AppInclude objects to specify whether a handler should be inserted at the beginning of the primary handler list or at the end. If 'tail' is specified, the handler is inserted at the end, otherwise, the handler is inserted at the beginning. This means that 'head' is the effective default. expiration: When used with static files and directories, the time delta to use for cache expiration. Has the form '4d 5h 30m 15s', where each letter signifies days, hours, minutes, and seconds, respectively. The 's' for seconds may be omitted. Only one amount must be specified, combining multiple amounts is optional. Example good values: '10', '1d 6h', '1h 30m', '7d 7d 7d', '5m 30'. Special cases: When defining a static_dir handler, do not use a regular expression in the url attribute. Both the url and static_dir attributes are automatically mapped to these equivalents: <url>/(.*) <static_dir>/\1 For example: url: /images static_dir: images_folder Is the same as this static_files declaration: url: /images/(.*) static_files: images/\1 upload: images/(.*) """ ATTRIBUTES = { URL: validation.Optional(_URL_REGEX), LOGIN: validation.Options(LOGIN_OPTIONAL, LOGIN_REQUIRED, LOGIN_ADMIN, default=LOGIN_OPTIONAL), AUTH_FAIL_ACTION: validation.Options(AUTH_FAIL_ACTION_REDIRECT, AUTH_FAIL_ACTION_UNAUTHORIZED, default=AUTH_FAIL_ACTION_REDIRECT), SECURE: validation.Options(SECURE_HTTP, SECURE_HTTPS, SECURE_HTTP_OR_HTTPS, SECURE_DEFAULT, default=SECURE_DEFAULT), HANDLER_STATIC_FILES: validation.Optional(_FILES_REGEX), UPLOAD: validation.Optional(_FILES_REGEX), HANDLER_STATIC_DIR: validation.Optional(_FILES_REGEX), MIME_TYPE: validation.Optional(str), EXPIRATION: validation.Optional(_EXPIRATION_REGEX), REQUIRE_MATCHING_FILE: validation.Optional(bool), HANDLER_SCRIPT: validation.Optional(_FILES_REGEX), POSITION: validation.Optional(validation.Options(POSITION_HEAD, POSITION_TAIL)), } COMMON_FIELDS = set([URL, LOGIN, AUTH_FAIL_ACTION, SECURE]) ALLOWED_FIELDS = { HANDLER_STATIC_FILES: (MIME_TYPE, UPLOAD, EXPIRATION, REQUIRE_MATCHING_FILE), HANDLER_STATIC_DIR: (MIME_TYPE, EXPIRATION, REQUIRE_MATCHING_FILE), HANDLER_SCRIPT: (POSITION), } def GetHandler(self): """Get handler for mapping. Returns: Value of the handler (determined by handler id attribute). """ return getattr(self, self.GetHandlerType()) def GetHandlerType(self): """Get handler type of mapping. Returns: Handler type determined by which handler id attribute is set. Raises: UnknownHandlerType when none of the no handler id attributes are set. UnexpectedHandlerAttribute when an unexpected attribute is set for the discovered handler type. HandlerTypeMissingAttribute when the handler is missing a required attribute for its handler type. """ for id_field in URLMap.ALLOWED_FIELDS.iterkeys(): if getattr(self, id_field) is not None: mapping_type = id_field break else: raise appinfo_errors.UnknownHandlerType( 'Unknown url handler type.\n%s' % str(self)) allowed_fields = URLMap.ALLOWED_FIELDS[mapping_type] for attribute in self.ATTRIBUTES.iterkeys(): if (getattr(self, attribute) is not None and not (attribute in allowed_fields or attribute in URLMap.COMMON_FIELDS or attribute == mapping_type)): raise appinfo_errors.UnexpectedHandlerAttribute( 'Unexpected attribute "%s" for mapping type %s.' % (attribute, mapping_type)) if mapping_type == HANDLER_STATIC_FILES and not self.upload: raise appinfo_errors.MissingHandlerAttribute( 'Missing "%s" attribute for URL "%s".' % (UPLOAD, self.url)) return mapping_type def CheckInitialized(self): """Adds additional checking to make sure handler has correct fields. In addition to normal ValidatedCheck calls GetHandlerType which validates all the handler fields are configured properly. Raises: UnknownHandlerType when none of the no handler id attributes are set. UnexpectedHandlerAttribute when an unexpected attribute is set for the discovered handler type. HandlerTypeMissingAttribute when the handler is missing a required attribute for its handler type. """ super(URLMap, self).CheckInitialized() self.GetHandlerType() def FixSecureDefaults(self): """Force omitted 'secure: ...' handler fields to 'secure: optional'. The effect is that handler.secure is never equal to the (nominal) default. See http://b/issue?id=2073962. """ if self.secure == SECURE_DEFAULT: self.secure = SECURE_HTTP_OR_HTTPS def WarnReservedURLs(self): """Generates a warning for reserved URLs. See: http://code.google.com/appengine/docs/python/config/appconfig.html#Reserved_URLs """ if self.url == '/form': logging.warning( 'The URL path "/form" is reserved and will not be matched.') def ErrorOnPositionForAppInfo(self): """Raises an error if position is specified outside of AppInclude objects. """ if self.position: raise appinfo_errors.PositionUsedInAppYamlHandler( 'The position attribute was specified for this handler, but this is ' 'an app.yaml file. Position attribute is only valid for ' 'include.yaml files.')
class AppInfoExternal(validation.Validated): """Class representing users application info. This class is passed to a yaml_object builder to provide the validation for the application information file format parser. Attributes: application: Unique identifier for application. version: Application's major version. runtime: Runtime used by application. api_version: Which version of APIs to use. handlers: List of URL handlers. default_expiration: Default time delta to use for cache expiration for all static files, unless they have their own specific 'expiration' set. See the URLMap.expiration field's documentation for more information. skip_files: An re object. Files that match this regular expression will not be uploaded by appcfg.py. For example: skip_files: | .svn.*| #.*# nobuild_files: An re object. Files that match this regular expression will not be built into the app. Go only. api_config: URL root and script/servlet path for enhanced api serving """ ATTRIBUTES = { APPLICATION: APPLICATION_RE_STRING, VERSION: validation.Optional(VERSION_RE_STRING), RUNTIME: RUNTIME_RE_STRING, API_VERSION: API_VERSION_RE_STRING, BUILTINS: validation.Optional(validation.Repeated(BuiltinHandler)), INCLUDES: validation.Optional(validation.Type(list)), HANDLERS: validation.Optional(validation.Repeated(URLMap)), LIBRARIES: validation.Optional(validation.Repeated(Library)), SERVICES: validation.Optional( validation.Repeated(validation.Regex(_SERVICE_RE_STRING))), DEFAULT_EXPIRATION: validation.Optional(_EXPIRATION_REGEX), SKIP_FILES: validation.RegexStr(default=DEFAULT_SKIP_FILES), NOBUILD_FILES: validation.RegexStr(default=DEFAULT_NOBUILD_FILES), DERIVED_FILE_TYPE: validation.Optional( validation.Repeated( validation.Options(JAVA_PRECOMPILED, PYTHON_PRECOMPILED))), ADMIN_CONSOLE: validation.Optional(AdminConsole), ERROR_HANDLERS: validation.Optional(validation.Repeated(ErrorHandlers)), BACKENDS: validation.Optional(validation.Repeated(backendinfo.BackendEntry)), THREADSAFE: validation.Optional(bool), API_CONFIG: validation.Optional(ApiConfigHandler), } def CheckInitialized(self): """Performs non-regex-based validation. The following are verified: - At least one url mapping is provided in the URL mappers. - Number of url mappers doesn't exceed MAX_URL_MAPS. - Major version does not contain the string -dot-. - If api_endpoints are defined, an api_config stanza must be defined. - If the runtime is python27 and threadsafe is set, then no CGI handlers can be used. - That the version name doesn't start with BUILTIN_NAME_PREFIX Raises: MissingURLMapping: if no URLMap object is present in the object. TooManyURLMappings: if there are too many URLMap entries. MissingApiConfig: if api_endpoints exist without an api_config. ThreadsafeWithCgiHandler: if the runtime is python27, threadsafe is set and CGI handlers are specified. """ super(AppInfoExternal, self).CheckInitialized() if not self.handlers and not self.builtins and not self.includes: raise appinfo_errors.MissingURLMapping( 'No URLMap entries found in application configuration') if self.handlers and len(self.handlers) > MAX_URL_MAPS: raise appinfo_errors.TooManyURLMappings( 'Found more than %d URLMap entries in application configuration' % MAX_URL_MAPS) if self.libraries: if self.runtime != 'python27': raise appinfo_errors.RuntimeDoesNotSupportLibraries( 'libraries entries are only supported by the "python27" runtime' ) library_names = [library.name for library in self.libraries] for library_name in library_names: if library_names.count(library_name) > 1: raise appinfo_errors.DuplicateLibrary( 'Duplicate library entry for %s' % library_name) if self.version and self.version.find( ALTERNATE_HOSTNAME_SEPARATOR) != -1: raise validation.ValidationError( 'Version "%s" cannot contain the string "%s"' % (self.version, ALTERNATE_HOSTNAME_SEPARATOR)) if self.version and self.version.startswith(BUILTIN_NAME_PREFIX): raise validation.ValidationError( ('Version "%s" cannot start with "%s" because it is a ' 'reserved version name prefix.') % (self.version, BUILTIN_NAME_PREFIX)) if self.handlers: api_endpoints = [ handler.url for handler in self.handlers if handler.GetHandlerType() == HANDLER_API_ENDPOINT ] if api_endpoints and not self.api_config: raise appinfo_errors.MissingApiConfig( 'An api_endpoint handler was specified, but the required ' 'api_config stanza was not configured.') if self.threadsafe and self.runtime == 'python27': for handler in self.handlers: if (handler.script and (handler.script.endswith('.py') or '/' in handler.script)): raise appinfo_errors.ThreadsafeWithCgiHandler( 'Threadsafe cannot be enabled with CGI handler: %s' % handler.script) def ApplyBackendSettings(self, backend_name): """Applies settings from the indicated backend to the AppInfoExternal. Backend entries may contain directives that modify other parts of the app.yaml, such as the 'start' directive, which adds a handler for the start request. This method performs those modifications. Args: backend_name: The name of a backend defined in 'backends'. Raises: BackendNotFound: If the indicated backend was not listed in 'backends'. """ if backend_name is None: return if self.backends is None: raise appinfo_errors.BackendNotFound self.version = backend_name match = None for backend in self.backends: if backend.name != backend_name: continue if match: raise appinfo_errors.DuplicateBackend else: match = backend if match is None: raise appinfo_errors.BackendNotFound if match.start is None: return start_handler = URLMap(url=_START_PATH, script=match.start) self.handlers.insert(0, start_handler)
class Name(validation.Validated): ATTRIBUTES = { 'name': validation.Optional( validation.Repeated(validation.Options('anders', 'stefan'))), }
class Application(validation.Validated): ATTRIBUTES = {'api_version': validation.Options('1', '1.2')}
class URLMap(validation.Validated): """Mapping from URLs to handlers. This class acts like something of a union type. Its purpose is to describe a mapping between a set of URLs and their handlers. What handler type a given instance has is determined by which handler-id attribute is used. Each mapping can have one and only one handler type. Attempting to use more than one handler-id attribute will cause an UnknownHandlerType to be raised during validation. Failure to provide any handler-id attributes will cause MissingHandlerType to be raised during validation. The regular expression used by the url field will be used to match against the entire URL path and query string of the request. This means that partial maps will not be matched. Specifying a url, say /admin, is the same as matching against the regular expression '^/admin$'. Don't begin your matching url with ^ or end them with $. These regular expressions won't be accepted and will raise ValueError. Attributes: login: Whether or not login is required to access URL. Defaults to 'optional'. url: Regular expression used to fully match against the request URLs path. See Special Cases for using static_dir. static_files: Handler id attribute that maps URL to the appropriate file. Can use back regex references to the string matched to url. upload: Regular expression used by the application configuration program to know which files are uploaded as blobs. It's very difficult to determine this using just the url and static_files so this attribute must be included. Required when defining a static_files mapping. A matching file name must fully match against the upload regex, similar to how url is matched against the request path. Do not begin upload with ^ or end it with $. static_dir: Handler id that maps the provided url to a sub-directory within the application directory. See Special Cases. mime_type: When used with static_files and static_dir the mime-type of files served from those directories are overridden with this value. script: Handler id that maps URLs to scipt handler within the application directory that will run using CGI. expiration: When used with static files and directories, the time delta to use for cache expiration. Has the form '4d 5h 30m 15s', where each letter signifies days, hours, minutes, and seconds, respectively. The 's' for seconds may be omitted. Only one amount must be specified, combining multiple amounts is optional. Example good values: '10', '1d 6h', '1h 30m', '7d 7d 7d', '5m 30'. Special cases: When defining a static_dir handler, do not use a regular expression in the url attribute. Both the url and static_dir attributes are automatically mapped to these equivalents: <url>/(.*) <static_dir>/\1 For example: url: /images static_dir: images_folder Is the same as this static_files declaration: url: /images/(.*) static_files: images/\1 upload: images/(.*) """ ATTRIBUTES = { URL: validation.Optional(_URL_REGEX), LOGIN: validation.Options(LOGIN_OPTIONAL, LOGIN_REQUIRED, LOGIN_ADMIN, default=LOGIN_OPTIONAL), HANDLER_STATIC_FILES: validation.Optional(_FILES_REGEX), UPLOAD: validation.Optional(_FILES_REGEX), HANDLER_STATIC_DIR: validation.Optional(_FILES_REGEX), MIME_TYPE: validation.Optional(str), EXPIRATION: validation.Optional(_EXPIRATION_REGEX), HANDLER_SCRIPT: validation.Optional(_FILES_REGEX), } COMMON_FIELDS = set([URL, LOGIN]) ALLOWED_FIELDS = { HANDLER_STATIC_FILES: (MIME_TYPE, UPLOAD, EXPIRATION), HANDLER_STATIC_DIR: (MIME_TYPE, EXPIRATION), HANDLER_SCRIPT: (), } def GetHandler(self): """Get handler for mapping. Returns: Value of the handler (determined by handler id attribute). """ return getattr(self, self.GetHandlerType()) def GetHandlerType(self): """Get handler type of mapping. Returns: Handler type determined by which handler id attribute is set. Raises: UnknownHandlerType when none of the no handler id attributes are set. UnexpectedHandlerAttribute when an unexpected attribute is set for the discovered handler type. HandlerTypeMissingAttribute when the handler is missing a required attribute for its handler type. """ for id_field in URLMap.ALLOWED_FIELDS.iterkeys(): if getattr(self, id_field) is not None: mapping_type = id_field break else: raise appinfo_errors.UnknownHandlerType( 'Unknown url handler type.\n%s' % str(self)) allowed_fields = URLMap.ALLOWED_FIELDS[mapping_type] for attribute in self.ATTRIBUTES.iterkeys(): if (getattr(self, attribute) is not None and not (attribute in allowed_fields or attribute in URLMap.COMMON_FIELDS or attribute == mapping_type)): raise appinfo_errors.UnexpectedHandlerAttribute( 'Unexpected attribute "%s" for mapping type %s.' % (attribute, mapping_type)) if mapping_type == HANDLER_STATIC_FILES and not self.upload: raise appinfo_errors.MissingHandlerAttribute( 'Missing "%s" attribute for URL "%s".' % (UPLOAD, self.url)) return mapping_type def CheckInitialized(self): """Adds additional checking to make sure handler has correct fields. In addition to normal ValidatedCheck calls GetHandlerType which validates all the handler fields are configured properly. Raises: UnknownHandlerType when none of the no handler id attributes are set. UnexpectedHandlerAttribute when an unexpected attribute is set for the discovered handler type. HandlerTypeMissingAttribute when the handler is missing a required attribute for its handler type. """ super(URLMap, self).CheckInitialized() self.GetHandlerType()
class AppInfoExternal(validation.Validated): """Class representing users application info. This class is passed to a yaml_object builder to provide the validation for the application information file format parser. Attributes: application: Unique identifier for application. version: Application's major version number. runtime: Runtime used by application. api_version: Which version of APIs to use. handlers: List of URL handlers. default_expiration: Default time delta to use for cache expiration for all static files, unless they have their own specific 'expiration' set. See the URLMap.expiration field's documentation for more information. skip_files: An re object. Files that match this regular expression will not be uploaded by appcfg.py. For example: skip_files: | .svn.*| #.*# """ ATTRIBUTES = { APPLICATION: APPLICATION_RE_STRING, VERSION: VERSION_RE_STRING, RUNTIME: RUNTIME_RE_STRING, API_VERSION: API_VERSION_RE_STRING, HANDLERS: validation.Optional(validation.Repeated(URLMap)), SERVICES: validation.Optional( validation.Repeated(validation.Regex(_SERVICE_RE_STRING))), DEFAULT_EXPIRATION: validation.Optional(_EXPIRATION_REGEX), SKIP_FILES: validation.RegexStr(default=DEFAULT_SKIP_FILES), DERIVED_FILE_TYPE: validation.Optional( validation.Repeated( validation.Options(JAVA_PRECOMPILED, PYTHON_PRECOMPILED))), ADMIN_CONSOLE: validation.Optional(AdminConsole), ERROR_HANDLERS: validation.Optional(validation.Repeated(ErrorHandlers)), } def CheckInitialized(self): """Ensures that at least one url mapping is provided. Raises: MissingURLMapping when no URLMap objects are present in object. TooManyURLMappings when there are too many URLMap entries. """ super(AppInfoExternal, self).CheckInitialized() if not self.handlers: raise appinfo_errors.MissingURLMapping( 'No URLMap entries found in application configuration') if len(self.handlers) > MAX_URL_MAPS: raise appinfo_errors.TooManyURLMappings( 'Found more than %d URLMap entries in application configuration' % MAX_URL_MAPS) def FixSecureDefaults(self): """Force omitted 'secure: ...' handler fields to 'secure: optional'. The effect is that handler.secure is never equal to the (nominal) default. See http://b/issue?id=2073962. """ if self.handlers: for handler in self.handlers: if handler.secure == SECURE_DEFAULT: handler.secure = SECURE_HTTP_OR_HTTPS def WarnReservedURLs(self): """Generates a warning for reserved URLs. See: http://code.google.com/appengine/docs/python/config/appconfig.html#Reserved_URLs """ if self.handlers: for handler in self.handlers: if handler.url == '/form': logging.warning( 'The URL path "/form" is reserved and will not be matched.' )
class HasOptions(v.Validated): ATTRIBUTES = { 'options': v.Options('a', 'b'), }
class BuiltinHandler(validation.Validated): """Class representing builtin handler directives in application info. Permits arbitrary keys but their values must be described by the validation.Options object returned by ATTRIBUTES. """ class DynamicAttributes(dict): """Provide a dictionary object that will always claim to have a key. This dictionary returns a fixed value for any get operation. The fixed value passed in as a constructor parameter should be a validation.Validated object. """ def __init__(self, return_value, **parameters): self.__return_value = return_value dict.__init__(self, parameters) def __contains__(self, _): return True def __getitem__(self, _): return self.__return_value ATTRIBUTES = DynamicAttributes( validation.Optional( validation.Options((ON, ON_ALIASES), (OFF, OFF_ALIASES)))) def __init__(self, **attributes): """Ensure that all BuiltinHandler objects at least have attribute 'default'. """ self.ATTRIBUTES.clear() self.builtin_name = '' super(BuiltinHandler, self).__init__(**attributes) def __setattr__(self, key, value): """Permit ATTRIBUTES.iteritems() to return set of items that have values. Whenever validate calls iteritems(), it is always called on ATTRIBUTES, not on __dict__, so this override is important to ensure that functions such as ToYAML() return the correct set of keys. """ if key == 'builtin_name': object.__setattr__(self, key, value) elif not self.builtin_name: self.ATTRIBUTES[key] = '' self.builtin_name = key super(BuiltinHandler, self).__setattr__(key, value) else: raise appinfo_errors.MultipleBuiltinsSpecified( 'More than one builtin defined in list element. Each new builtin ' 'should be prefixed by "-".') def ToDict(self): """Convert BuiltinHander object to a dictionary. Returns: dictionary of the form: {builtin_handler_name: on/off} """ return {self.builtin_name: getattr(self, self.builtin_name)} @classmethod def IsDefined(cls, builtins_list, builtin_name): """Find if a builtin is defined in a given list of builtin handler objects. Args: builtins_list: list of BuiltinHandler objects (typically yaml.builtins) builtin_name: name of builtin to find whether or not it is defined Returns: true if builtin_name is defined by a member of builtins_list, false otherwise """ for b in builtins_list: if b.builtin_name == builtin_name: return True return False @classmethod def ListToTuples(cls, builtins_list): """Converts a list of BuiltinHandler objects to a list of (name, status).""" return [(b.builtin_name, getattr(b, b.builtin_name)) for b in builtins_list] @classmethod def Validate(cls, builtins_list): """Verify that all BuiltinHandler objects are valid and not repeated. Args: builtins_list: list of BuiltinHandler objects to validate. Raises: InvalidBuiltinFormat if the name of a Builtinhandler object cannot be determined. DuplicateBuiltinSpecified if a builtin handler name is used more than once in the list. """ seen = set() for b in builtins_list: if not b.builtin_name: raise appinfo_errors.InvalidBuiltinFormat( 'Name of builtin for list object %s could not be determined.' % b) if b.builtin_name in seen: raise appinfo_errors.DuplicateBuiltinsSpecified( 'Builtin %s was specified more than once in one yaml file.' % b.builtin_name) seen.add(b.builtin_name)
class AppInfoExternal(validation.Validated): """Class representing users application info. This class is passed to a yaml_object builder to provide the validation for the application information file format parser. Attributes: application: Unique identifier for application. version: Application's major version number. runtime: Runtime used by application. api_version: Which version of APIs to use. handlers: List of URL handlers. default_expiration: Default time delta to use for cache expiration for all static files, unless they have their own specific 'expiration' set. See the URLMap.expiration field's documentation for more information. skip_files: An re object. Files that match this regular expression will not be uploaded by appcfg.py. For example: skip_files: | .svn.*| #.*# """ ATTRIBUTES = { APPLICATION: APPLICATION_RE_STRING, VERSION: VERSION_RE_STRING, RUNTIME: RUNTIME_RE_STRING, API_VERSION: API_VERSION_RE_STRING, BUILTINS: validation.Optional(validation.Repeated(BuiltinHandler)), INCLUDES: validation.Optional(validation.Type(list)), HANDLERS: validation.Optional(validation.Repeated(URLMap)), SERVICES: validation.Optional( validation.Repeated(validation.Regex(_SERVICE_RE_STRING))), DEFAULT_EXPIRATION: validation.Optional(_EXPIRATION_REGEX), SKIP_FILES: validation.RegexStr(default=DEFAULT_SKIP_FILES), DERIVED_FILE_TYPE: validation.Optional( validation.Repeated( validation.Options(JAVA_PRECOMPILED, PYTHON_PRECOMPILED))), ADMIN_CONSOLE: validation.Optional(AdminConsole), ERROR_HANDLERS: validation.Optional(validation.Repeated(ErrorHandlers)), } def CheckInitialized(self): """Performs non-regex-based validation. Ensures that at least one url mapping is provided in the URL mappers Also ensures that the major version doesn't contain the string -dot-. Raises: MissingURLMapping when no URLMap objects are present in object. TooManyURLMappings when there are too many URLMap entries. """ super(AppInfoExternal, self).CheckInitialized() if not self.handlers and not self.builtins and not self.includes: raise appinfo_errors.MissingURLMapping( 'No URLMap entries found in application configuration') if self.handlers and len(self.handlers) > MAX_URL_MAPS: raise appinfo_errors.TooManyURLMappings( 'Found more than %d URLMap entries in application configuration' % MAX_URL_MAPS) if self.version.find(ALTERNATE_HOSTNAME_SEPARATOR) != -1: raise validation.ValidationError( 'App version "%s" cannot contain the string "%s"' % (self.version, ALTERNATE_HOSTNAME_SEPARATOR))
class Optioned(validation.Validated): ATTRIBUTES = { 'color': validation.Options('red', 'green', 'blue'), 'size': validation.Options('big', 'small', 'medium') }